I’ve set up a self-referencing relationship model for users to be friends with one another. I am able to create a friend request (two entries in my DB, one for the friendship and one for the inverse friendship) without any problems.
I am having trouble declining a friend request though. I keep getting this error when I press decline which takes me to the destroy action:
NoMethodError in FriendshipsController#destroy
undefined method `destroy' for nil:NilClass
One of the database records, pending friendship, is destroyed even though I get the error above, and if I comment out @friendship2 = @user.friendships.find_by_friend_id(params[:id]).destroy, the other record gets destroyed too. So it looks like both line are work individually, but returns the above error.
SOLUTION: It looks like my two destroy statements were referencing the same record. I’ve commented out the wrong code in my controller and added the ones that work for me.
Here is my Friendships controller:
class FriendshipsController < ApplicationController
before_filter :authenticate, :only => [:update, :create, :destroy]
def create
@user = User.find(current_user)
@friend = User.find(params[:friend_id])
params[:friendship1] = {:user_id => @user.id, :friend_id => @friend.id, :status => 'requested'}
params[:friendship2] = {:user_id => @friend.id, :friend_id => @user.id, :status => 'pending'}
@friendship1 = Friendship.create(params[:friendship1])
@friendship2 = Friendship.create(params[:friendship2])
redirect_to @friend
end
end
def destroy
@user = User.find(params[:user_id])
@friend = User.find(params[:id])
#@friendship2 = @user.friendships.find_by_friend_id(params[:id]).destroy
#@friendship1 = @friend.friendships.find_by_id(params[:user_id]).destroy
@friendship1 = @user.friendships.find_by_friend_id(@friend.id).destroy #removes the requested friendship
@friendship2 = @friend.friendships.find_by_friend_id(@user.id).destroy #removes the pending friendship
flash[:success] = "Removed."
redirect_to @user
end
end
Here is my User model:
class User < ActiveRecord::Base
has_many :friendships, :dependent => :destroy
has_many :friends,
:through => :friendships,
:conditions => "status = 'accepted'",
:source => :friend
has_many :pending_friends,
:through => :friendships,
:conditions => "status = 'pending'",
:foreign_key => "user_id",
:source => :friend
has_many :requested_friends,
:through => :friendships,
:source => :friend,
:conditions => "status = 'requested'"
end
Here is my view (users/show.html.erb):
<% if signed_in? && @user == current_user %>
<% unless current_user.pending_friends.empty? %>
<h2>Pending</h2>
<% current_user.pending_friends.each do |pending| %>
<%= pending.name %>
<%= link_to '[Accept]', friendship_path(:user_id => current_user, :id => pending), :method => :put, :confirm => "Accept?" %>
<%= link_to '[Decline]', friendship_path(:user_id => current_user, :id => pending), :method => :delete, :confirm => "Decline?" %>
<% end %>
<% end %>
<% end %>
I have two questions.
-
I’ve seen from some tutorials/discussion about the use of inverse_friendships, but is this really necessary? So far, I haven’t seen the need for this, but then again, I’ve only gotten as far as coding my create and destroy action.
-
What’s up with the undefined method ‘destroy’ error?
Thanks for getting through this wall of text! 😀
Regarding the first one, it’s up to you and your system. Creating different variable to hold every type of friendship might be a bit hardcore though, but it gives you full information, more control and there’s no data duplication in the database.
Regarding the second one you should check whether your query return a result. Since your exception:
Says there’s no method “destroy” in NilClass (not friendship). Just check the :id parameter and whether find_by_friend_id returns anything at all.