1

Trying to find the mutual relation, In a friends relations, Already have friends and inverse_friends. But how to combine them to get the mutual friends? Cannot seem to figure it out I tried several options and searched long time online, just don't see it

  has_many :friendships
  has_many :friends, :through => :friendships
  has_many :inverse_friendships, :class_name => "Friendship", :foreign_key => "friend_id"
  has_many :inverse_friends, :through => :inverse_friendships, :source => :user

how to get a

has_many :mutual_friends ?
Ken Y-N
  • 14,644
  • 21
  • 71
  • 114
Rubytastic
  • 15,001
  • 18
  • 87
  • 175
  • It would be easier to address your question if you posted the table definitions so we didn't have to guess about your schema. – Alex Blakemore Sep 17 '12 at 23:06

3 Answers3

5

Do you need two models to find mutual friends?

Couldn't you just do

@mutualfriends = @user1.friends & @user2.friends
Robert
  • 543
  • 2
  • 6
  • 17
  • By mutual_friends, I think he means reciprocated friendships. ie there's a user1.id|user2.id entry and a user2.id|user1.id entry in the friendships table. – Mark Peterson Feb 20 '13 at 21:42
  • 1
    This is an elegant solution. But there is a small drawback: it returns `Array`, so you might not be able to send methods that you would send to `ActiveRecord` objects. (i.e. paginate, decorate, etc.) – mc9 Nov 24 '14 at 07:54
3

I don't think you can define a mutual friends association. So, let's look at a mutual friends class method or scope.

I assume that we want all our friends, for whom we are their friend.

class User
  has_many :friendships
  has_many :friends, :through => :friendships
  has_many :inverse_friendships, :class_name => "Friendship", :foreign_key => "friend_id"
  has_many :inverse_friends, :through => :inverse_friendships, :source => :user

  def mutual_friends
    inverse_friends.joins(:friendships).where("friendships.user_id = users.id and friendships.friend_id = :self_id", :self_id => id).all
  end
end

To do it as an association, this would be what you are trying to do:

has_many :mutual_friends,
         :through => :inverse_friendships,
         :source => :user,
         :conditions => ["friendships.user_id = users.id and friendships.friend_id = :self_id", :self_id => id]

The problem is with the id method call in the has_many :mutual_friends association definition.

Marlin Pierce
  • 9,931
  • 4
  • 30
  • 52
  • I had a rough Idea this could be solved with a def method but trying your solution throws a undefined local variable or method `inverse_friends' when Im trying to access the data in my view with " for user in User.mutual_friends puts @user.username end – Rubytastic Sep 18 '12 at 07:34
  • if you would want an extra .where statement in there how would to process that? .where('game_id = 1). doesent work. thx – Rubytastic Sep 19 '12 at 08:56
  • It should go with the other where, before or after. However, because of all the joins, and joins to the same table, you may need to qualify game_id with the table name, "friendships.game_id", and you may have to look at the SQL in the log to find how ActiveRecord is naming the tables with the joins to the same table. (Looking at the SQL you might solve the problem with the association. I edited my answer with help, maybe a hint for using an association.) – Marlin Pierce Sep 19 '12 at 10:07
  • Look here http://guides.rubyonrails.org/active_record_basics.html#schema-conventions under primary keys. – Marlin Pierce Sep 08 '16 at 15:27
2

try the intersection of two querys here is a thread about that

Intersection of two relations

Community
  • 1
  • 1
Rodrigo Zurek
  • 4,555
  • 7
  • 33
  • 45