Self-Referential Relationships
Tuesday, April 29th, 2008I’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/xxxcreaterelationships.rb
class CreateRelationships < ActiveRecord::Migration
def self.up
createtable :relationships do |t|
t.integer :userid, :friendid
t.string :relationshiptype
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
hasmany :relationships
hasmany :friends, :through => :relationships
end
And in our relationship.rb model:
app/models/user.rb
class Relationship < ActiveRecord::Base
belongsto :friend, :classname => "User"
belongs_to :user
end
And now we see if it works:
script/console
>> u = User.findbyname("Ryan")
=> #
u.friends << User.findbyname("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 findrelationshipwith(user)
Relationship.findbyfriendid(user.toi)
end
The first method, toi, will return just the id for the user. The reason why we do this is because in the next method, findrelationshipwith we pass in a single argument, user. Now because we’ve defined the toi 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.
