Self-referential Associations

Self-referential Associations with rails 4

When I first heard about this concept I was a little bit confuse. I remenber when I was doing the tutorial Learn rails by Example by Michael Hart, excellent first start, at the end of the book we implemented a self referential associations. By that time the concept was to much for me, so I did some research. I found Railscast episode Self-referential Associations, it threw some light in the concept, but I still confuse.

Right now I think I understand the concept a little bit better but there always room for improvement. I’m going to show you the code for a simple self-referential association for friends and followers.

1
2
3
4
5
6
7
8
9
10
11
12
13
class User < ActiveRecord::Base
  has_many :reviews
  has_many :queue_items, -> {order(:position)}
  has_many :friendships, foreign_key: :user_id
  has_many :followers, class_name: "Friendship", foreign_key: :friend_id

  has_secure_password validations: false
  validates_presence_of :full_name, :email

  def included_in_queue?(video)
    queue_items.include?(video)
  end
end

I have to say that Ryan Bates solution probably is more efficient than this one but for me this one looks more clear.

Ok, so we have a User model and a Friendship model that has user_id and friend_id. Now is time to link this two models. The line has_many :friendships, foreign_key: :user_id is telling ActiveRecord::Base to get all row from the friendships table where user_id and the current_user.id match.

This is the query:

1
SELECT "friendships".* FROM "friendships"  WHERE "friendships"."user_id" = ?  [["user_id", 1]]

Thanks to the method has_many and some of the options we are able to get what we want, the option foreign_key let us specify the foreign key used for the association.

The last line has_many :followers, class_name: "Friendship", foreign_key: :friend_id let us get the people that are following us.

Because there is no followers table we have to specify the class_name in this case Friendships and the foreign_key option will help us specify the association.

This is the query:

1
SELECT "friendships".* FROM "friendships"  WHERE "friendships"."friend_id" = ?  [["friend_id", 1]]

I’m sure there are probably more better ways to do it but this one help me understand it better.

Comments