Question

I can't seem to get Amistad friendships to work correctly. I am getting the following error:

ActiveRecord::RecordNotFound in FriendshipsController#update
Couldn't find Friendship with id=29

I am also using devise and cancan. I followed the gem setup on the wiki pages and created my controller as described in this related post.

class FriendshipsController < ApplicationController

  before_filter :authenticate_user!

  def index
    @friends = current_user.friends
    @pending_invited_by = current_user.pending_invited_by
    @pending_invited = current_user.pending_invited
  end

  def create
    @friend = User.find(params[:user_id])
    @friendship_created = current_user.invite(@friend)
    if @friendship_created
      redirect_to users_path, :notice => "Your friend request is pending"
    end
  end

  def update
    @friend = User.find(params[:user_id])
    @friends = current_user.friends
    @pending_invited_by = current_user.pending_invited_by
    redirect_to users_path, :notice => "You are now friends!"
  end

  def destroy
    @friend = User.find(params[:user_id])
    @friendship = current_user.send(:find_any_friendship_with, @friend)
    if @friendship
      @friendship.delete
      @removed = true
      redirect_to users_path, :notice => "You are no longer friends!"
    end
  end

  def createblock
    @friend = User.find(params[:user_id])
    current_user.block @friend

    redirect_to users_path, :notice => "You have blocked #{@friend.first_name}"
  end

end

I loop though my users in the following manner checking the current status of the user and offering appropriate actions.

<% if current_user.friend_with? user  %>
     <%= link_to "Unfriend", friend_path(user), :method => "delete", :class => 'btn btn-mini' %>
<% elsif current_user.invited? user  %>
     <span class="btn btn-mini disabled">Pending</span>
<% elsif user.invited? current_user  %>
     <%= link_to "Accept", friend_path(user), :method => "put", :class => 'request-approve btn btn-mini' %>
     <%= link_to "Decline", friend_path(user), :method => "delete", :class => 'request-decline btn btn-mini' %>
<% else %>
     <%= link_to "Add friend", friends_path(:user_id => user), :method => "post", :class => 'btn btn-mini' %>
<% end %>

Figured it would be useful to see what the friendships table looks like in my schema:

create_table "friendships", :force => true do |t|
    t.integer "friendable_id"
    t.integer "friend_id"
    t.integer "blocker_id"
    t.boolean "pending",       :default => true
  end

  add_index "friendships", ["friendable_id", "friend_id"], :name => "index_friendships_on_friendable_id_and_friend_id", :unique => true

I understand the error just cannot figure out how this should change. I think my issue is that I am passing in a friend id and it is expecting a friendship id. My only problem with this solution is that every example or post I can find suggests passing user_id, like this post above where the answerer states the gem developer supplied the code he answers with.

What I feel like I need in my update method is to replace:

@friend = User.find(params[:id])

With this:

@friendship = Friendship.find_by_friend_id(params[:id])

EDIT I can successfully request a friend, I just cannot accept or decline a friend. I a listing of users, clicking the "Add Friend" link creates the record in the friendships db correctly. If I log ins as that recently requested user and attempt to accept the request is when I get the above error. This also occurs if I attempt to decline the request.

The friends method you asked to see come with the amistad gem, here is the code for that method. As for my Ruby logs the section that displays the error was very long, so I have included it in this gist.

Was it helpful?

Solution 2

The lookup problem is because you're passing ids inconsistently. In 3 of the links, you're passing the User object directly, which should automatically store the id in params[:id], which you can use in your action as User.find(params[:id]). But in your actions, you're extracting it from params[:user_id], which is empty. Not sure how you're getting an ID of 29 in your error message (or 32 or whatever), but...

If you change all your actions to expect params[:id] and switch the "Add friend" path link to pass in a User object the way the others already are, you should be passing the right data in the right parameter, and the lookup should straighten itself out.

Of course, as Wonky Business points out, you're not actually calling approve in your update method, so nothing will actually link, but at least you should be finding all your model objects.

As an aside, it appears from your paths you're remapping the friendship named routes to friend instead. That's muddling the issue because none of the RESTful routes are actually doing what their noun/verb combination implies: if you call friends_path(user) with a POST, there should be a new Friend object when you're done, but this controller is creating and destroying Friendship objects and leaving the Friend objects alone.

If you delete that alias and switch to friendship_path and so forth, then REST will actually be doing what it says it is: managing friendship objects.

Hope that helps!

OTHER TIPS

Given my current reputation, I can only post an answer instead of a comment to your question but as far as I can see from the controller sources you posted, you are not calling current_user.approve @friend in your update action.

I used this gem in one of my projects recently without running into any problems. The controller actions look like this:

def update
  @friend = User.find_by_id(params[:id])
  if current_user.approve @friend
    redirect_to friendships_path, notice: t('.confirmation_successful')
  else
    redirect_to friendships_path, alert: t('.confirmation_unsuccessful')
  end
end

def destroy
  @friend = User.find_by_id(params[:id])
  if current_user.remove_friendship @friend
    redirect_to friendships_path, notice: t('.deletion_successful')
  else
    redirect_to friendships_path, alert: t('.deletion_unsuccessful')
  end
end

I hope this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top