has_many :through, self referential models


Hat tip to [has_many :through self-referential example] that sent me down the correct path on this. The challenge I had went a little deeper than the aforementioned post, however. I’m going to reuse the friend example, but with a twist.

class Person < ActiveRecord::Base
  # id :integer
end
class Friendship < ActiveRecord::Base
  # source_friend_id :integer
  # target_friend_id :integer
end

In the above contrived example, Person is a friend who initiated the friendship (source_friend), and a friend that was sought for friendship (target_friend). For the friendship, reflection won’t work on either connection, so we need to specify the class_name:.

class Friendship < ActiveRecord::Base
  belongs_to :source_friend, class_name: "Person"
  belongs_to :target_friend, class_name: "Person"
end

Including the friendship would normally be easy. That’s has_many :friendships. However, there’s no explicit mapping back to Person for the Friendship. ActiveRecord will attempt to use friendships.person_id to no avail, so foreign_key must be specified to tell ActiveRecord how to map back the has_many relationship.

  class Person < ActiveRecord::Base
    has_many :friendships, foreign_key: :source_friend_id
  end

Now, the friends you’ve “made” can be mapped by putting the target_friend as the source for the has_many :through.

  class Person < ActiveRecord::Base
    has_many :friendships, foreign_key: :source_friend_id
    has_many :made_friends, through: :friendships, source: :target_friend
  end

%d bloggers like this: