how to set up relationships in rails with friends or followers


How to Set up Relationships in Rails with Friends or Followers

Creating social relationships between users is a core functionality of any social networking site or web application. A good relationship system should allow users to make connections with each other, send friend requests, follow other users, and view their friends and followers. In this article, we’ll explore how to set up relationships in Rails with friends or followers.

Introduction

Defining relationships between data entities is one of the fundamentals of web development. In the context of social networking sites, a relationship is a connection between two users that can be categorized into different types such as friendship and following.

Building a reliable relationship management system can improve user experience and engagement on your platform. Ruby on Rails is an excellent framework for creating social features due to its strong database modeling capabilities and easy-to-use migration system.

In this article, we’ll explore how to set up relationships in Rails with friends or followers using models, migrations and associated methods for building out our social features.

Setting Up Relationships

Before diving into setting up individual relationships like friendships or followers in Rails, it’s essential to understand the core concepts of relationship modeling.

There are different types of relationships which are:

  • One-to-one
  • One-to-many
  • Many-to-many

In the context of a social media app, we’ll typically use many-to-many relationships since most users will have more than one friend or follower.

To accomplish this in Rails, we need to define a model that represents our relationship table. A simple way to achieve this is by creating a new file called ‘relationship.rb’ in the ‘models’ folder in your application.

The Relationship Model

We’ll create our relationship model as follows:

rails generate model Relationship user_id:integer friend_id:integer status:string

The ‘status’ column here has a default value of ‘pending’, which indicates that a relationship invitation has not been accepted. You can also add timestamps by passing in --timestamps to the generator.


Migrations for Relationships

Now that our model is set up, the next step is to create a migration file. We’ll use the following command to create it:

rails generate migration CreateRelationships

In the generated file, we’ll specify the schema for our relationship model as follows:

“`
class CreateRelationships < ActiveRecord::Migration[6.1] def change create_table :relationships do |t| t.integer :user_id t.integer :friend_id t.string :status, default: 'pending' t.timestamps end add_index :relationships, [:user_id, :friend_id], unique: true end end ``` The command above creates a new table in our database called ‘relationships’. After this, we add index for user_id and friend_id fields to ensure uniqueness such that no two records will have the same combination of user_id and friend_id. Next, run rails db:migrate from the terminal to record these changes in your database.


Adding Associations to Models

After defining our relationships and migrations, we can now associate them with our models.

We need to specify relationships between users and their friends/followers. This can be achieved through associations in Rails.

There are three association types in Rails — belongs_to, has_one/many and has_and_belongs_to_many (HABTM).

  • belongs_to: is used when a model record belongs to a single parent record, e.g. for messages or comments.
  • has_one/many: is used when a model record has one or many children records, e.g. in case of posts and comments relationship.
  • has_and_belongs_to_many: is used when a model record can have many children records through multiple parents records, e.g. for friends or followers relationship between users.

We’ll first specify the associations for our Relationship models as shown below:

“`
class Relationship < ApplicationRecord belongs_to :user belongs_to :friend, class_name: "User" end ``` Here we’ve specified that each 'relationship' will belong to a 'user', and that the 'friend' field should be associated with 'User' model with an alias of ‘friend’. To complete the association, we’ll add definitions in our User model as follows: ``` class User < ApplicationRecord has_many :relationships has_many :friends, through: :relationships end ``` In this example, we’re using has_many associations for relationship and friends. Note that the ‘through’ option specifies the path to find friends.

Note: It’s important to define all associations in both models involved in the relationship.


Testing Relationships

After defining our migrations and models along with their respective associations, it’s essential to also test our relationships to ensure everything is set up correctly.

Rails comes with a built-in framework called ‘RSpec’ which enables creating tests for your application.

Rspec-Rails uses Ruby’s ‘expectation syntax’ which makes it easy to read and write tests.

Below is a simple example of testing that a user has many friends:

“`
describe ‘User’ do
it ‘has an association’ do
u = User.reflect_on_association(:friends)
expect(u.macro).to eq(:has_many)
end
end
“`

You can run your tests by typing rspec in the terminal.

Setting up Friends Relationship

Setting up friendships involves connecting individuals, who must both approve the friendship requests.

To set this up, we’ll create an additional table that will store friendships related data with friend_id and user_id fields as well as a column called ‘status’ specific for friendship purposes.

This field will allow us to represent different states in the life cycle of a friendship relationship, such as ‘pending’, ‘accepted’ and ‘rejected’.

Adding these extra columns will enable us to represent friendships correctly in our models and thus be able to accept or decline friend requests.

Let’s take a look at how the Friendship model might look:

The Friendship Model

We’ll be creating a new file called ‘friendship.rb’ in models folder using this command:

rails generate model Friendship user_id:integer friend_id:integer status:string

The next step is to create a migration for our Friendship model. We’ll use this command to generate the migration:

rails generate migration CreateFriendships

In our migration file, we’ll add the following code to describe the schema for our friendship model:

“`
class CreateFriendships < ActiveRecord::Migration[6.1] def change create_table :friendships do |t| t.references :user, null: false, foreign_key: true t.references :friend, null: false, foreign_key: {to_table: :users} t.string :status t.timestamps end end end ``` In this model, we’ve specified that each Friendship will belong to a user and a friend of a user. The status column will hold the status for each friendship instance. After creating the Friendship model and migration, it’s time to add associations to our models.

Add Associations to Models

In our User model, we’ll add associations as shown below:

“`
class User < ApplicationRecord has_many :friendships, dependent: :destroy has_many :inverse_friendships, class_name: 'Friendship', foreign_key: 'friend_id', dependent: :destroy has_many :friends, through: :friendships, source: 'friend' has_many :inverse_friends, through: :inverse_friendships, source: 'user' def self.friends?(user_one_id, user_two_id) Friendship.where(user_id: [user_one_id,user_two_id], friend_id:[user_one_id,user_two_id], status: "accepted").count == 2 end end ``` We’re using has_many and belongs_to associations to define the relationships between users and friendships. To find a user’s accepted friends or inverse-friends, we’re using the ‘through’ option to specify associations using friendships. The last method friends? is defined to check if two given user_ids are already friends by checking number of records with “status” as “accepted” between both. We also need to define associations in our Friendship model as shown below: ``` class Friendship < ApplicationRecord belongs_to :user belongs_to :friend, class_name: 'User' end ``` The user and friend fields are two-way foreign keys references in our Friendship model. This means that when we create a new friendship record, the record will automatically be associated with both the user and the friend.

Defining Methods for Requesting and Accepting Friendships

Next, we’ll define methods that will help us to request and accept friendships.

“`
class Friendship < ApplicationRecord def self.request(user, friend) unless user == friend || Friendship.exists?(user: user, friend: friend) transaction do create!(user: user, friend: friend, status: 'pending') create!(user: friend, friend: user, status: 'requested') end end end def self.accept(user,friend) request = where(user: user, friend: friend,status:'pending').first reverse_request = where(user:friend,friend:user,status:"requested").first if request && reverse_request transaction do friends!(request) end else false end end private def self.friends!(request) request.update(status:'accepted') reverse_request.update(status:'accepted') Friendship.create!(user:request.user,friend:request.friend,status:'accepted') Friendship.create!(friend:request.user,user:request.friend,status:'accepted') end end ``` The request method will initiate a pending friendship from the primary user’s account to a second account. The accept method which accepts the friendships needs to confirm that two records exist before making any changes their ‘status’ flag. If two records are found in “pending” and “requested”, which implies that there is a connection pending between two users then it goes ahead and update both records to show the status as accepted. When we have added these two methods to our application codebase we can call them using these lines of code below: ``` Friendship.request(user_1,user_2) Friendship.accept(user_1,user_2) ```

Implementing User Interface for Sending and Accepting Friend Requests

In Rails, we can use the existing CRUD functionality to implement our user interface for manually sending and accepting friend requests.

The first step is to create a form that allows users to send a friend request. This can be done by generating a new Rails controller using the scaffold command:

“`
rails g scaffold FriendRequest sender:integer receiver:integer status:string
“`

The next step is to generate appropriate actions in our friend request controller.

When writing code for the templates, it’s essential to have some validation on both sender and receiver’s ID fields with dropdowns if possible.

We make these changes to our migration for friend requests:

“`
class CreateFriendRequests < ActiveRecord::Migration[6.1] def change create_table :friend_requests do |t| t.references :sender, null: false, foreign_key: {to_table: :users} t.references :receiver, null: false, foreign_key: {to_table: :users} t.string :status,default: 'pending' t.timestamps end end end ``` Finally, we update our models User and FriendRequest by adding the associations as shown below: ``` class User < ApplicationRecord has_many :sent_friend_requests, class_name: 'FriendRequest', foreign_key: 'sender_id' has_many :received_friend_requests, class_name: 'FriendRequest', foreign_key: 'receiver_id' end class FriendRequest < ApplicationRecord belongs_to :sender, class_name: 'User' belongs_to :receiver, class_name: 'User' end ```

Setting up Followers Relationship

A one-way following relationship refers to someone who follows another person without requiring explicit approval from that person.

To create a following relationship, we’ll add an additional table to store the follow data. This follows the same pattern as we did with friendship but this time, it will have only one column referring to user_id and another referring to a follower’s id.

The Follow Model

We’ll create a new file called ‘follow.rb’ in models folder using the command below:

rails generate model Follow user_id:integer follower_id:integer

After generating the Follow model file, we’ll create the migration file using the command below:

rails generate migration CreateFollows

In the migration file, we’ll describe the schema for Follow class as shown below:

“`
class CreateFollows < ActiveRecord::Migration[6.1] def change create_table :follows do |t| t.references :user, null: false, foreign_key: true t.references :follower, null: false, foreign_key: {to_table: :users} t.timestamps end add_index :follows, [:user_id, :follower_id], unique: true end end ``` In this migration, we’ve defined that each follow record belongs to one user while followers belong to users as well. The second line of code specifies that followers are references to users model and they are referenced using their ID column. After creating our migration for our Follow model, we’ll need to add our associated models.

Add Associations to Models

Inside our User model, we’ll add the following associations:

“`
class User < ApplicationRecord has_many :follows, dependent: :destroy has_many :followers_relationships, class_name: 'Follow', foreign_key: 'follower_id', dependent: :destroy has_many :following_users, through: :follows, source: 'follower' has_many :followers, through: :followers_relationships, source: 'user' end ``` In the above code snippet, we have specified two sets of associations. One is for the users who are following one or more other users. The second is for any user who has one or several followers. Next up is defining follow and unfollow models using class methods.

Defining Methods for Following and Unfollowing Users

After creating associations to our User model, a couple of new class methods need to be defined on our Follow model to facilitate users to follow and unfollow relationships as defined below:

“`
class Follow < ApplicationRecord def self.follow(user_id, follower_id) create(user_id: user_id,follower_id:follower_id) end def self.unfollow(user_id,follower_id) where("user_id=? and follower_id=?", user_id, follower_id).destroy_all end end ``` After adding these methods to our application logic, we can simply invoke them like this: ``` Follow.follow(current_user.id,params[:id]) Follow.destroy(current_user.id,params[:id]) ```

Implementing User Interface for Following and Unfollowing Users

Like with friend requests relationship implementation, we’ll also use standard Rails CRUD functionality and partials to create a UI that will allow users to follow and unfollow other users seamlessly.

The first step to creating a user interface is generating the Follow controller using the scaffold command in Terminal:

“`
rails g scaffold FollowRelationship following_id:integer follower_id:integer
“`

Advanced Topics in Setting up Relationships with Friends or Followers

The core functionalities of a relationship system are explained in detail

7 FAQs about Setting Up Relationships in Rails with Friends or Followers

1. What is the difference between a friend and a follower in Rails?

A friend relationship is mutual, meaning both users must confirm the friendship request. Follower relationships are one-sided, where one user can follow another without confirmation from the other user.

2. How do I set up user relationships in Rails?

You can use gems like “acts_as_follower” or “acts_as_friendable” to set up user relationships in Rails. These gems provide easy-to-use methods for creating and managing relationships between users.

3. Can users have both friends and followers?

Yes, users can have both friends and followers in Rails. The two types of relationships are not mutually exclusive.

4. How do I display a list of a user’s friends or followers?

You can use the “friends” or “followers” methods provided by the “acts_as_friendable” or “acts_as_follower” gems to retrieve a list of a user’s friends or followers, respectively. Then, you can display this list however you like using Rails’ built-in view templates.

5. Can I customize the information displayed about each relationship?

Yes, you can customize the information displayed about each relationship by modifying the views associated with the “acts_as_friendable” or “acts_as_follower” gems. Most commonly, users will display profile pictures and names for each friend or follower.

6. How do I allow users to delete friendships or followers?

You can use the “destroy_friendship!” or “unfollow!” methods provided by the “acts_as_friendable” or “acts_as_follower” gems, respectively. These methods will remove the relationship between users and update any associated records (such as friend/follower counts).

7. Is there a way to limit the number of friends or followers a user can have?

Yes, you can add custom validations to your user model to enforce limits on the number of friends or followers a user can have. For example, you could add a validation that prevents users from having more than 500 followers.

keys takeaways

4 Key Takeaways for Setting Up Relationships in Rails with Friends or Followers

1. Understand the Relationship Model

Before starting to set up relationships in Rails, it’s important to understand the relationship model that best fits your needs. Consider whether you need a simple friend-relationship or a more complex follow-relationship.

2. Use Appropriate Associations

Once you have decided on the relationship model, use appropriate associations like has_many, belongs_to, and has_many through to connect different models. Code these associations effectively for easy retrieval of data between associated models.

3. Create Validations

To ensure the integrity of your data and improve user experience, it’s crucial to create validations for the relationships between models. Validate unique combinations of friend_id and follower_id and establish their presence in tables for seamless functionality.

4. Optimize the Display of Relationships

One key factor in developing social networks is optimizing the display of relationship management: be it choosing styles for followers and friends counts or incorporating sorting functionality based on those counts. Consider using authentication techniques like Devise Gem and utilizing jQuery to make the interface sleek and intuitive.

By following these four key takeaways, setting up rich relationships in Rails with friends or followers will become a breeze.