Creating an app is a process, and thinking of an idea worth implementing on its own can be a monumental task. But once that idea pops into your head, the idea you're very sure about, you're determined to make it appear just as beautifully on the screen. This, of course, is all easier said than done.
The time came to develop my first app, and I had this wonderful idea (the kind described above), but I had no idea how to implement it! Despite learning everything I needed to write the foundations of an app, I felt overwhelmed. To make things easier, I sat down and wrote on pen and paper the things I wanted for my app.
- Users/profiles
- Posts
- Followers/following relationships
While this is only three things, it's three major things! Of course, my app has to have users, and it makes sense that those users would have posts. But following relationships? How could I do that. When I first looked at the words, I thought about using something like a hash or an array that would hold all the followers for a user. Although what I will make will be similar, a basic array or hash would be a very inefficient way of programming, only leaving problems for later. After learning ActiveRecord and Sinatra, I knew there had to be a better way. There was! Tables and table relationships.
After creating my users and posts tables/models, I created a follow model. My Follow class appeared as following:
class Follow < ActiveRecord::Base
belongs_to :follower, foreign_key: 'user_id', class_name: "User"
belongs_to :following, foreign_key: 'following_id', class_name: "User"
end
So reading this, we could say that a 'follower' belongs to a follow (since you are following someone). Instead of creating a new table 'Follows', I assigned a foreign_key of 'user_id' to 'follower', joining to the User class. We would then read the next statement as a 'following' belongs to a follow (since that is the act of following another user), again with a foreign_key, but this time it is 'following_id' (the other user id), pulled from the User class. Creating this relationship with foreign keys cuts out the need to create and migrate a new table (not to say that it wouldn't need to be done in the future depending on what your app does).As confusing as it seems, after reading it over a couple times it will start to make sense!
But we're not finished yet! My User class also needed some adjustments to accommodate the new relationship.
has_many :follows
has_many :follower_relationships, foreign_key: :following_id, class_name: "Follow"
has_many :followers, through: :follower_relationships, source: :follower
has_many :following_relationships, foreign_key: :user_id, class_name: "Follow"
has_many :following, through: :following_relationships, source: :following
Since, the user will hopefully be following many accounts, it has many follows. Since it has many follows, it will also has many 'follower relationships', this is through the foreign key 'following_id' established in the Follow class. Next a user will has many 'followers' through the 'follower relationships' just created, while also using the 'follower' foreign_key created from 'user_id' in the Follow class. Again we have a similar snippet of code, except we are substituting the foreign key and source ('following'), since this is the followee of the relationship. Not too bad right?
I can't credit this all to my own, I read a few other blog posts that recited other programmers attempts and successes at creating following relationships (one of them being here, shout out to all you awesome people!) But what I will give back the web of wonders, is how I created my post methods for the actual act of following and unfollowing (oof!) someone. Creating and getting (unintentional pun there) these methods to work was a bit of a pain, but unlike me, you have this (hopefully helpful) blog post! Alright, let's get to it!
I created a followers_controller, and started with my follow method.
class FollowersController < ApplicationController
post '/users/:id/follow' do
follow_user = User.find_by_id(params[:id])
if !current_user.following.include?(follow_user)
current_user.following << follow_user
end
if !follow_user.followers.include?(current_user)
follow_user.followers << current_user
end
redirect '/following'
end
get '/following' do
erb :'/users/following'
end
To create a follow, I made a post request to '/users/:id/follow', in this case the 'id' is the user_id of the person being followed, NOT the current user a.k.a you. This follow_user is the equivalent of the following made in the Follow class. This may get a bit confusing, so hang in there! In the next line of code:
if !current_user.following.include?(follow_user)
I use following again, but through the has many and following relationships made in the User class. Here checks to see if the current user (you) has a following_relationship including the follow_user (the followee). If it doesn't, the follow_user (followee) will be appended into the following_relationships (similar to a fictional table of users and the people they follow, and vice versa).
if !follow_user.followers.include?(current_user)
follow_user.followers << current_user
end
In the next few lines of code, the same thing is happening except, now instead of adding a follow_user (followee) to a user, we are adding a user to follow_user (followee). The last few snippets demonstrate a get path I made that directs the user to a page of everyone they follow. And there you have it, we made a follow post request!
Making an unfollow request, believe it or not, is even easier!
Using the same route, but switching 'follow' to 'unfollow', we can do the request in three simple lines. Like before, I set the follow_user to the user_id (This is the user_id of the user being unfollowed). Then with one if statement, I checked to see the follow_user has myself, the 'current user' stored in their followers. If I, the current user, was stored in the followers, my next line of code destroys myself from the list of users inside followers. I then no longer follow that user! Pretty easy, right?
post '/users/:id/unfollow' do
follow_user = User.find_by_id(params[:id])
if follow_user.followers.include?(current_user)
follow_user.followers.destroy(current_user)
end
redirect "/following"
end
end
While I encourage reading more into following relationships and the actions that come along with them, this blog post should cover enough basics to implement follows in your own app. I hope you were able to follow along!
Top comments (1)
Thanks for sharing your journey in implementing following relationships in your app! Your use of ActiveRecord and the Follow class for creating relationships is insightful. The step-by-step explanation, along with TopFollow code snippets, makes it easier for others to understand and implement in their projects. Kudos for breaking down the process, and best of luck with your app development!