Like many newbie coders, I wanted to stretch my newly learned Rails skills and thought building a simple travel review/social media site would be best. Building the basic MVCs for Users, Reviews, Destinations was pretty straight forward. The real trouble started when I tried to give users the ability to follow and unfollow on another. I struggled (longer than I care to admit) to build out this feature, and I figured I couldn’t be the only one. My hope is that this step by step guild will help others breakthrough the same issues I experienced and in the process, selfishly, help me to solidify what I learned.
Step 1: Make a Relationships Table
The basic setup for the Relationships table is pretty straightforward: two columns for the foreign keys titled follower_id and followed_id. Naturally, both columns will contain integers. The labeling of these columns is relative to your project as these keys will both truly be User ids. However, they do need to be labeled something unique to avoid conflict as they will be used throughout the project, specifically in a
has_many: relationships in the User model.
Step 2: Modify the User Model
The next step focuses on relating the User model to the Relationship model with a has_many, belongs_to structure, respectively. The User will have many Relationships via the foreign keys labeled in the first step (follower_id and followed_id). For this project, I want the User to be able to follow another User without forcing a symbiotic follow relationship. Also, since the two foreign keys are actually the same type of entity (User-User) entering into the Relationship, I need to provide these relations with a unique label, while telling the User model that these are instances of the Relationship class. Rails provides a convenient way to find the relationships between records in the database. In this project, I labeled the two different instances as
:passive_relationship, where the
:active_relationship is related to the follower_id and the
:passive_relationship is matched with the followed_id. Again, these labels are relative and can be called whatever makes the most sense to your project. If you notice in the code below, I did add
dependent: :destroy to the end of the code. This ensures the data from the Relationship table is deleted if a User deletes their profile.
Step 3: Build the Relationship Model
Now the Relationship model needs to be told which user is following and which user is being followed. To do that, we need to build out two
belongs_to: statements relative to two different instances of the User class. In this project, I titled these follower_user and followed_user, but again, these are arbitrary. As with the User
has_many: statements, I need to make sure the Relationships model knows which foreign key is associated with the different instances. As you may have guessed, the follower_user is related to the follower_id and the followed_user is related to the followed_id.
Step 4: Modify the User Model, Again
I now need to add the ability to find these follower_users and followed_users through the Relationship model. The code added to the User model is nearly identical to that written in the Relationship model. The main difference is that the User knows about these instances through either the active_relationships or passive_relationships.
Step 5: Build the Relationship Controller
Before I even touch the controller part, I want to add routes to map out the actions I want to use. For my project, the Relationship Controller will only need
:index. The first two are pretty intuitive since I want someone using my site to be able to follow and unfollow other users. The
:index is to give me the ability to listing the user’s relationships on their profile. Again, make sure that the routes you add make sense to your overall project.
Finally, I can build out the controller. The most straightforward method is the index. I have a helper method in my Application Controller called current_user, which finds the user using the
session[:user_id]. I won’t go into more detail here, but there is plenty of literature online outlining the basic structure behind this method. Using this helper method, I want to find all the active_relationships and passive_relationships for the current user and save these to variables that I can then access in my Views.
Next, I add the destroy method as this, to me, is another fairly straightforward method. First, I need to find the relationship I want to delete using the
:id and save that to a variable. To give my code some layer of protection, I want to ensure that the current_user matches the follower_user in this relationships. Once that is verified, I then delete the instance from my table and give the user a message stating that the action was successful. For my project, this action will be done on the followed_user profile, and I want the current user to have that same page reload, i.e. redirect_to to the same page.
Finally, I want to build out the create method that will allow a user to follow someone. This one, for me, is the most challenging logic wise, but again, is fairly similar to other create methods I used in my project. Initially, I need to find followed_user and assign it to a variable. This variable will be used to assign the followed_id and for the redirect_to path. Next, I want to build the active_relationship from the current_user and again, assign this to a variable to be used in the Views. Again, to give the user feedback, if the relationship can be saved, the user will see the message "Follow Successful." Otherwise, the user will see "Follow Unsuccessful."
The only thing left to do is add these methods to my Views. As I am still in the process of refining the look and feel of these individual pages, I will end my walkthrough here. Again, there is additional literature available online as to how people gave different buttons or links the functionality to use these methods. As I have found, there is more than one way to do things in Rails. Thanks for reading and I would love to hear more thoughts or insight into how others built out their own social website. Cheers!