I’ve seen this question asked time and time again, so I’m going to write a short tutorial about how to do it. The question is self-refferential relationships for a model, often the User model to determine the relationship between two different users. I’ll assume that you’ve already got a Rails application and at least a User model for this. We’ll use a has_many :through relationship to define which users are related to who.
Let’s generate a model for the relationship: script/generate model relationship. This will generate a migration which we’ll create our relationships table with.
db/migrate/xxx_create_relationships.rb
class CreateRelationships < ActiveRecord::Migration
def self.up
create_table :relationships do |t|
t.integer :user_id, :friend_id
t.string :relationship_type
end
end
def self.down
drop_table :relationships
end
end
And that should do us. Run rake db:migrate to add the table in.
Now we go into our User model and we add in the following:
app/models/user.rb
class User < ActiveRecord::Base
has_many :relationships
has_many :friends, :through => :relationships
end
And in our relationship.rb model:
app/models/user.rb
class Relationship < ActiveRecord::Base
belongs_to :friend, :class_name => "User"
belongs_to :user
end
And now we see if it works:
script/console
>> u = User.find_by_name("Ryan")
=> #
>> u.friends << User.find_by_name("Charlie")
=> #
>> u.save
=> true
Now what if we want to change that relationship field? We’ll add in two methods in to the user model to find the relationship for a specific user.
app/models/user.rb
def to_i
id
end
def find_relationship_with(user)
Relationship.find_by_friend_id(user.to_i)
end
The first method, to_i, will return just the id for the user. The reason why we do this is because in the next method, find_relationship_with we pass in a single argument, user. Now because we’ve defined the to_i method on our User model, this means we can either pass in a user id or a user object to this method, and it will call to_i on whatever we pass in, ending up with an id. When the method’s done, it will return a relationship object which you can then modify.
Best of luck.