Friendship System Rails 3.0

I am trying to develop a friendship system like facebook. I have follow for guidance the two following sources

How to Implement a Friendship Model in Rails 3 for a Social Networking Application? Railsspace book chapter 14, which can only be downloaded i believed I am a bit confused on the way railsspace has been building there relationship. What i am trying to do his to show in a views my pending_request, accepted_request and declined_request. The books seem to suggest the following relationship

FriendshipModel

class Friendship < ActiveRecord::Base   belongs_to :customer   belongs_to :friend, :class_name => 'Customer', :foreign_key => 'friend_id' CustomerModel

class Customer < ActiveRecord::Base #RELATIONSHIP     has_many :friendships     has_many :friends, :through => :friendships,          :conditions => "status = 'accepted'"     has_many :requested_friends,          :through => :friendships,          :source => :friend,          :conditions => "status = 'requested'"     has_many :pending_friends,          :through => :friendships,          :source => :friend,          :conditions => "status = 'pending'" The issues i am having his how can i access friends who are pendings, friends who are requested. I have the following view in my index (friendship/index)

<div><h1>Request</h1></div> <table>   <% @customer.friends.each do |friend| %>   <tr>     <td><%= link_to friend.first_name, '#' %></td>   </tr>   <% end %> </table> But i get the following errors

NoMethodError in Friends#index

Showing /app/views/friends/index.html.erb where line #15 raised:

undefined method `friends' for #<Array:0xb6144040> Extracted source (around line #15):

12: 13: <div><h1>Request</h1></div> 14: <table> 15: <% @customer.friends.each do |friend| %> 16: <tr> 17: <td><%= link_to friend.first_name, '#' %></td> 18: </tr> Mind you, my model is called friendship, my controller his called friends ( not the best name but its more for practise learning I did)

Here the model

# Table name: friendships

undefined method `friends' for #<Array:0xb6144040>

You didn't show us the controller code that defines @customer but I'll bet you used something returned an array when you wanted a single object.

Also, be sure to note that Rails 3.1 finders return ARels (active record relation objects) which are array-like, pre-Rails 3.1 you get an actual array. So you get some funny business when upgrading from pre-Rails 3.1 to Rails 3.1 or higher when doing stuff like this, because ARels can behave like Arrays but aren't actually arrays.

Jason Fb wrote in post #1072568:

undefined method `friends' for #<Array:0xb6144040>

You didn't show us the controller code that defines @customer but I'll bet you used something returned an array when you wanted a single object.

Interesting about the Arel thing but here the controller

class FriendsController < ApplicationController

  before_filter :setup_friends

  def index     @customer = Customer.all   end

  #Send a friend request   def create     Friends.request(@customer, @friend)   end

  private     def setup_friends       @customer = current_customer       @friend = Customer.find_by_id(params[:id])     end end

You seem to have defined @customer twice, once in the setup_friends method which is run first as a before_filter hook, and then again in the index method. the one in the index method returns an array, since you asked for @customer.all

Jason Fb wrote in post #1072573:

You seem to have defined @customer twice, once in the setup_friends method which is run first as a before_filter hook, and then again in the index method. the one in the index method returns an array, since you asked for @customer.all

Sorry for the late reply, after notice I did change many thing. ( redid from scracth)

So here an updated code

Friendship Model ( and rename table to friendship ) class Friendship < ActiveRecord::Base

  belongs_to :customer   belongs_to :friend, :class_name => 'Customer', :foreign_key => 'friend_id'

  validates_presence_of :customer_id, :friend_id   attr_accessible :approved, :customer_id, :friend_id

#Method   # Return true if the customers are (possibly pending) friends.   def self.exists?(customer, friend)     not find_by_customer_id_and_friend_id(customer, friend).nil?   end

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

  # Accept a friend request.   def self.accept(customer, friend)     transaction do       accepted_at = Time.now       accept_one_side(customer, friend, accepted_at)       accept_one_side(friend, customer, accepted_at)     end   end

  # Delete a friendship or cancel a pending request.   def self.breakup(customer, friend)     transaction do       destroy(find_by_customer_id_and_friend_id(customer, friend))       destroy(find_by_customer_id_and_friend_id(friend, customer))     end   end

  private

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

Customer Model class Customer < ActiveRecord::Base ... #RELATIONSHIP

  has_many :friendships   has_many :friends, :through => :friendships,      :conditions => "status = 'accepted'"   has_many :requested_friends,      :through => :friendships,      :source => :friend,      :conditions => "status = 'requested'"   has_many :pending_friends,      :through => :friendships,      :source => :friend,      :conditions => "status = 'pending'" end

Controller Friendship class FriendshipsController < ApplicationController

  before_filter :setup_friends

  def accept     if @customer.requested_friends.include?(@friend)       Friendship.accept(@customer, @friend)       flash[:notice] = "Friendship Accepted"     else       flash[:notice] = "No Friendship request"     end     redirect_to root_url   end

  def decline     if @customer.requested_friends.include?(@friend)       Friendship.breakup(@customer, @friend)       flash[:notice] = "Friendship Declined"     else       flash[:notice] = "No Friendship request"     end     redirect_to root_url   end

  def cancel     if @customer.pending_friends.include?(@friend)       Friendship.breakup(@customer, @friend)       flash[:notice] = "Friendship Canceled"     elserequested       flash[:notice] = "No Friendship request"     end     redirect_to root_url   end

  def delete     if @customer.friends.include?(@friend)       Friendship.breakup(@customer, @friend)       flash[:notice] = "Friendship Deleted"     else       flash[:notice] = "No Friendship request"     end     redirect_to root_url   end

  def index     @customers = Customer.all   end

  #Send a friendship request   def create     Friendships.request(@customer, @friend)   end

  private     def setup_friends       @customer = current_customer       @friend = Customer.find_by_id(params[:id])     end end

Now here the issue i seem to not really understand but is to manager the relationship and here my code atm. This is in index.html.erb from friendship and list everything, <div><h1>Friends</h1></div>

<% @customer.friends.each do |friend| %>   <%= link_to friend.incomplete_name, '#' %><br /> <% end %>

<div><h1>Request</h1></div>

<% @customer.requested_friends.each do |rf| %>   <%= link_to rf.incomplete_name, '#' %><br /> <% end %>

<div><h1>Pendings</h1></div>

<% @customer.pending_friends.each do |pf| %>   <%= link_to pf.incomplete_name, '#' %><br /> <% end %>

<div><h1>Users</h1></div> <% @customers.each do |customer| %>   <% if current_customer != customer %>   <div><%= friendship_status(current_customer, customer) %></div>     <% unless Friendship.exists?(current_customer, customer) %>       <%= link_to "Request friendship with #{customer.first_name}",     { :controller => "friendships", :action => "create",   :id => customer.id },   :confirm =>   "Send friend request to #{customer.incomplete_name}?" %>       <% end %>   <% end %> <% end %>

In railspace they use an email link to accept, but i don't want to send an email and not sure how to refresh page with the proper information.

Thanks in advance

I doubt whether anyone has time to wade through all that code in order to understand your problem (though I may be proved wrong). You must try to ask a more specific question.

Colin

Colin Law wrote in post #1072687:

I doubt whether anyone has time to wade through all that code in order to understand your problem (though I may be proved wrong). You must try to ask a more specific question.

Colin

I understand and didn't want at first because its a lot of code, but just wanted to make sure it was understood properly ( language barrier sometime). Anyway

I am trying to create a relationship among the users, in my controller I have 2 function create and accept.

When clicking in my view file I have link_to which create the friendship. <%= link_to "Request friendship with #{customer.first_name}",     { :controller => "friendships", :action => "create",   :id => customer.id },   :confirm =>   "Send friend request to #{customer.incomplete_name}?" %>

However I do not see when refreshing that a friendship has really been created. In what ever states

I believe the issue is here

  has_many :requested_friends,      :through => :friendships,      :source => :friend,      :conditions => "status = 'requested'"

I am just suppose to say @customer.requested_friends and this would allow me iterate through each of them??

Thanks again

Colin Law wrote in post #1072687:

I doubt whether anyone has time to wade through all that code in order to understand your problem (though I may be proved wrong). You must try to ask a more specific question.

Colin

I understand and didn't want at first because its a lot of code, but just wanted to make sure it was understood properly ( language barrier sometime). Anyway

I am trying to create a relationship among the users, in my controller I have 2 function create and accept.

When clicking in my view file I have link_to which create the friendship. <%= link_to "Request friendship with #{customer.first_name}",     { :controller => "friendships", :action => "create",   :id => customer.id },   :confirm =>   "Send friend request to #{customer.incomplete_name}?" %>

Are you using a GET request to create records in the database? This is generally considered a bad idea.

However I do not see when refreshing that a friendship has really been created. In what ever states

So has it been created or not? Look directly at the database if necessary, to check. If not then get that working first before worrying about any views. Run rails console then you can do things like Friendship.all and it will show them all. In addition you can run any ruby code to interrogate the db in the same way as you do in the app (using find and so on).

I believe the issue is here

  has_many :requested_friends,      :through => :friendships,      :source => :friend,      :conditions => "status = 'requested'"

I am just suppose to say @customer.requested_friends and this would allow me iterate through each of them??

Yes, but check first as I said above that you are creating the friendships correctly first. I am sure I have pointed you to the Rails Guide on debugging already, but if not then have a look at it.

Colin