1

I am working on social media site and I have everything working in friendship except mutual friends. I cannot make it work.

This is my User model:

has_many :friendships
has_many :friends, -> { where(friendships: {status: 'accepted'}).order('created_at') }, :through => :friendships
has_many :requested_friends, -> { where(friendships: {status: 'requested'}).order('created_at') }, :through => :friendships, :source => :friend
has_many :pending_friends, -> { where(friendships: {status: 'pending'}).order('created_at') }, :through => :friendships, :source => :friend

Friendship Model:

class Friendship < ActiveRecord::Base
  belongs_to :user
  belongs_to :friend, :class_name => 'User', :foreign_key => 'friend_id'

  validates_presence_of :user_id, :friend_id

  # Create a friendship request.
  def self.send_request(user, friend)
    unless user == friend or Friendship.exists?(user, friend)
      transaction do
        create(:user => user, :friend => friend, :status => 'pending')
        create(:user => friend, :friend => user, :status => 'requested')
      end
    end
  end

  # Accept a friend request.
  def self.accept_request(user, friend)
    transaction do
      accept_one_side(user, friend)
      accept_one_side(friend, user)
    end
  end

  # Decline a request, disconnect or cancel a pending request.
  def self.breakup(user, friend)
    transaction do
      destroy(find_by_user_id_and_friend_id(user, friend))
      destroy(find_by_user_id_and_friend_id(friend, user))
    end
  end

  # Return true if the users are (possibly pending) friends.
  def self.exists?(user, friend)
    not find_by_user_id_and_friend_id(user, friend).nil?
  end

  private
  # Update the db with one side of an accepted friendship request.
  def self.accept_one_side(user, friend)
    request = find_by_user_id_and_friend_id(user, friend)
    request.status = 'accepted'
    request.save!
  end
end

I tried this: rails activerecord, friend relation + inverse_friend relation how to get the mutual relation? code included but still I cannot make it work.

Thank you.

Community
  • 1
  • 1
cyonder
  • 852
  • 1
  • 15
  • 36

3 Answers3

0

Given that you have two users, their mutual friends are simply:

user1.friends & user2.friends

Or is that not what you are looking for?

This might optimise it handily.

user1.friends.where(users: {id: user2.friends.pluck(:id)})
David Aldridge
  • 51,479
  • 8
  • 68
  • 96
0

If you define mutual as "common friends" for user a and user b, then this method should do the trick:

class Friendship
  def self.mutual(a,b)
    a.friends.joins('INNER JOIN friendships f2 on friendships.friend_id = f2.friend_id')
             .where('f2.user_id=? and f2.status = ?', b.id, 'accepted')
  end
end
dimakura
  • 7,575
  • 17
  • 36
0

I think is better to create a separate function like this

    def mutuals(user)
      a_friends = friends
      b_friends = user.friends
      a_friends.select do |friend|
        b_friends.find_by(friend_id: friend.friend_id)
      end
    end

with this method you can call @user.mutual(User.find(3)) to find mutual friends between the @user variable and user with id of 3