How to Implement a Friendship Model in Rails 3 for a Social Networking Application

How to Implement a Friendship Model in Rails 3 for a Social Networking Application?

To access all pending friendships you can use an association:

has_many :pending_friends,
:through => :friendships,
:source => :friend,
:conditions => "confirmed = 0" # assuming 0 means 'pending'

To make the friendship bidirectional, you may want to replace your boolean confirmed column with a string status column that has one of the following three values: 'pending', 'requested' and 'accepted' (optionally 'rejected'). This will help keep track of who made the friendship request.

When a friendship request is sent (say from Foo to Bar), you create two friendship records (encapsulated in a transaction): one requested and one pending to reflect resp. that Bar has a requested friendship from Foo and Foo has a pending friendship with Bar.

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

When the friendship is accepted (e.g. by Bar), both friendship records are set to accepted.

  def self.accept(user, friend)
transaction do
accepted_at = Time.now
accept_one_side(user, friend, accepted_at)
accept_one_side(friend, user, accepted_at)
end
end

def self.accept_one_side(user, friend, accepted_at)
request = find_by_user_id_and_friend_id(user, friend)
request.status = 'accepted'
request.accepted_at = accepted_at
request.save!
end

This is largely covered in chapter 14 of the Railspace book by Michael Hartl and Aurelius Prochazka. Here's the source code which should help you refine your solution.

the best way to implement a friendship model in rails

I would prefer the version that needs two connections between the friends, one for each direction. The reason is the same you mentioned: It allows more Rails-like queries on a user's friends.

Furthermore I think it would be clearer to have different tables for friendship request (one direction) and existing friendships (two directions)

Since you have a friendship model in the middle, I suggest to use the magic of callbacks. If you define some callbacks, it must be possible that you only have to take cake for one side of the connection, the callback should should be able to create (or delete) the matching complement.

# in friendship_requests
after_save :created_friendship

def accept
update_attributes(:status => 'accepted')
end

private
def created_friendship
sender.friends << receiver if status_changed? && status == 'accepted'
end


# in user.rb
has_and_belongs_to_many :friends, after_add: :create_complement_friendship,
after_remove: :remove_complement_friendship

private
def create_complement_friendship(friend)
friend.friends << self unless friend.friends.include?(self)
end

def remove_complement_friendship(friend)
friend.friends.delete(self)
end

This is just a first idea, for sure some validators and callbacks are missing...

Best database architecture for friendships in a social networking application

I would recommend the second model, separate tables for friend_request and friendship. While these tables may currently hold the exact same data, over time I would expect that they will diverge.

Here are some possible ways this might happen:-

  • you want to allow them to send a message along with the friend request ("Hey, remember me from school")
  • you decide you want to keep statistics about the friend request, such as when the request was made
  • you decide you want to keep declined friend requests in the database (to disallow further requests once declined)

Because they are different things, you should create different tables rather than overloading a single table. It's not so difficult to create a table.

Should you put two rows in the table, representing both directions of the relationship? This is a question of normalisation vs performance.

The normalised answer is to only include a single row. This model:

  • is easier to get update/insert/delete as there is only one row to worry about
  • more difficult and slower to query as you will need to query from both directions

The de-normalised answer (because duplicated data is stored) is to include both rows: This model:

  • is harder to update/insert/delete as there are two rows to keep synchronized
  • faster to query as you can query from just one direction

Ruby on rails 3 friendship

You need to separate the @customer and @friend. In your link, you are setting :friend_id to the customer, and you are never setting the @customer id.

Try this:

def create
@customer = current_account
@friend = Account.find(params[:friend_id])
Friendship.request(@customer, @friend)
redirect
end

In the link_to you need:

<%= link_to "Add Friend", friendships_path(:friend_id => friend),: method => :post %>

how to create a friendship model on Rails 5

you can use the 'has_friendship' gem for this.

This gem is really simple to use

  1. Create the migration rails generate has_friendship

  2. Add to the model

    class User < ActiveRecord::Base
    has_friendship
    end
  3. and you can start to manage your friends

Managing friendship

# Create Friends 
@joe = User.create(name: "Joe")
@doe = User.create(name: "Doe")

# @joe sends a friend request to @doe
@joe.friend_request(@doe)

# @doe can accept the friend request
@doe.accept_request(@joe)

# @doe can also decline the friend request
@doe.decline_request(@joe)

# @doe removes @joe from its friends
@doe.remove_friend(@joe)

again you can find more info on the gem Documention site https://github.com/sungwoncho/has_friendship

I hope that this helps :)

user has many :users, or must I use another way for a friend based social network?

I would suggest that a user has many relationships, this would leave you free to add new types of relationships in the future.

So you start with a "one user to another user" relationship table (minimally, just two IDs) and then in the future you could add a "one user to a group" relationship table (once you've created groups of course!)



Related Topics



Leave a reply



Submit