Q:

Implement a friendship model with has_and_belongs_to_many in rails

I have user model and I am using has_and_belongs_to_many on Rails to make a relation between user and friend model.
User can has many friends and friend can has many friends. I need to get all friends of specific user, how can I do that? 
In user.rb file:
has_and_belongs_to_many :friendships, class_name: "User", join_table:  :friendships,
                          foreign_key: :user_id,
                          association_foreign_key: :friend_user_id}

In 20180309142447_create_friendships_table.rb file:
class CreateFriendshipsTable < ActiveRecord::Migration[5.1]
  def change
    create_table :friendships, id: false do |t|
      t.integer :user_id
      t.integer :friend_user_id
    end

    add_index(:friendships, [:user_id, :friend_user_id], :unique => true)
    add_index(:friendships, [:friend_user_id, :user_id], :unique => true)
  end
end

I need to get all friends of specific user, how can I do that ? 

A:

Implementing a friendship between two users
I assume you are willing to implement a friendship pattern like Facebook:

User requests friendship for another user
Other other has to accept the friendship request
Only after these two steps the users are real friends

For this we need a friendship model which replaces your has_many_and_belongs_to-built in function. The friendship models will help us to identify active and pending friendship requests between users. The friendship model only has a user (initiator) and a friend (whom the user sent the request).
Scenario:

You send a request to Joe -> friendship model created, you are the 'user', joe is the 'friend'
Joe accepts your friendship -> friendship model created, joe is the 'user', you are the 'friend'
With 2 helper functions active_friends and pending_friends you can get the data for your views or API

# new migration
# $ rails g migration create_friendships
def change
  create_table :friendships do |t|
    t.integer :user_id
    t.integer :friend_id
    t.timestamps null: false
  end
end

create a new friendship model
# friendship.rb
class Friendship < ActiveRecord::Base

  # - RELATIONS
  belongs_to :user
  belongs_to :friend, class_name: 'User'

  # - VALIDATIONS
  validates_presence_of :user_id, :friend_id
  validate :user_is_not_equal_friend
  validates_uniqueness_of :user_id, scope: [:friend_id]

  def is_mutual
    self.friend.friends.include?(self.user)
  end

  private
  def user_is_not_equal_friend
    errors.add(:friend, "can't be the same as the user") if self.user == self.friend
  end

end

in your User model you can handle the friendships rails-like
# user.rb
has_many :friendships, dependent: :destroy
has_many :friends, through: :friendships

to get the friendships someoneelse sent to "you"
has_many :received_friendships, class_name: 'Friendship', foreign_key: 'friend_id'
has_many :received_friends, through: :received_friendships, source: 'user'

def active_friends
  friends.select{ |friend| friend.friends.include?(self) }  
end

def pending_friends
  friends.select{ |friend| !friend.friends.include?(self) }  
end

