0

So I have a User model (don't we all? :D) in my Rails application. A User can add friends.

I am following the answers given here: Model design: Users have friends which are users

User.rb

class User < ApplicationRecord
  ...
  has_and_belongs_to_many :friends,
    class_name: "User",
    join_table: :friends_users,
    foreign_key: :user_id,
    association_foreign_key: :friend_id

  ...
end

I have generated my migration file using:

rails generate CreateFriendshipJoinTable users friends

The resulting migration file with some modification:

Migration File

class CreateFriendshipsJoinTable < ActiveRecord::Migration[5.0]
  def change
    create_join_table :users, :friends do |t|
      t.index [:user_id, :friend_id]
      t.index [:friend_id, :user_id]
    end
  end
end

Update Action

def update
    user = User.find_by({id: params[:id]})

    skip_authorization and render status: :not_found and return unless user

    authorize user

    attributes = policy(User).permitted_attributes_for_update

    if user.update_attributes!(params.permit(attributes))
        render json: user
    else
        render status: :unprocessable_entity
    end
end

Test

  test "user friends - should successfully add a friend" do
    put user_path(@jim), params: {user_id: @sarah.id}, headers: user_authenticated_header(@jim)
    assert_response :success

    json = JSON.parse(response.body)
    puts "json = #{json}"

    user = User.find_by({id: @jim.id})
    assert_includes user.friends, @sarah
  end

My test fails.

I am not sure what the parameter to the HTTP PUT request is to tell my User the "friend" id is some number and that my User update action should find other User using given friend id and add that user as a friend of first user.

I am however, able to use rails console --sandbox successfully to add friends by creating two users, then using this code:

jim.friends << sarah

This adds Sarah as a friend of Jim as expected, which leads me to believe my table relationship is...half...working?

Any ideas anyone? :D

Community
  • 1
  • 1
Zhang
  • 11,549
  • 7
  • 57
  • 87

1 Answers1

0

I decided to use a different approach and created a new action called "add_friend":

def add_friend
  friend = User.find_by({id: params[:id]})

  skip_authorization and render status: :not_found and return unless friend

  authorize friend

  current_user.friends << friend
  friend.friends << current_user

  if current_user.save! && friend.save!
    render json: current_user, status: :ok
  else
    render status: :bad_request
  end
end

My test is passing now and my user Jim has a friend Sarah :D

Although, I will need to refactor this logic later to include friend invite/requests before actually connecting them up.

Zhang
  • 11,549
  • 7
  • 57
  • 87