How to add liking and unliking in rails

George
Full$taxx
Published in
3 min readApr 16, 2018

Week 2 of our Makers Academy engineering project has commenced. We have had a great experience so far with rails and now feel like we are getting to grips with the more complicated aspects. This guide is a quick introduction into adding likes to posts.

Create the controller and model

First you will need to generate the model:

rails g model Like post:references user:references

Then, migrate the table:

rails db:migrate

And finally, add the controller:

rails g controller likes

Add the create method to the controller

class LikesController < ApplicationController
before_action :find_post
def create
@post.likes.create(user_id: current_user.id)
redirect_to post_path(@post)
end
private def find_post
@post = Post.find(params[:post_id])
end
end

In app/views/posts/show.html.erb add this code:

<%= button_to 'Like', post_likes_path(@post), method: :post %>

In routes.rb nest the comments resource inside the posts resource:

resources :posts do
resources :likes
end

Now establish the one to many relationship between posts/users and likes. You do this like so:

In app/models/post.rb and app/models/user.rb add the line:

has_many :likes, dependent: :destroy

The first part gives the relation between the posts/users and their likes. The second part makes sure that when you delete a post/user, all their likes get deleted.

In app/views/posts/show.html.erb add this line to display how many likes a post has:

<p><%= @post.likes.count %> <%= (@post.likes.count) == 1 ? 'Like' : 'Likes'%></p>

Then, in app/views/posts/index.html.erb add this line to display how many likes a post has in the homepage:

<p><%= post.likes.count %> <%= (post.likes.count) == 1 ? 'Like' : 'Likes'%></p>

This is to show the number of likes. The bit of logic afterwards is to change to Like or Likes depending on the number.

Stop people liking more than once

First we need to add a method to check if a user has already liked a photo. Under the word private, add:

def already_liked?
Like.where(user_id: current_user.id, post_id:
params[:post_id]).exists?
end

Then edit your create method to account for it

def create
if already_liked?
flash[:notice] = "You can't like more than once"
else
@post.likes.create(user_id: current_user.id)
end
redirect_to post_path(@post)
end

The ‘if’ statement checks if there is a like in the database with the current user_id and the current post_id, which means they must have already liked. If so we don’t add another like and flash an error message.

Adding the unlike feature

In the likes controller we need to add a destroy method:

def destroy
if !(already_liked?)
flash[:notice] = "Cannot unlike"
else
@like.destroy
end
redirect_to post_path(@post)
end

In this method I also make sure they don’t unlike when they haven’t liked.

In order to delete a like you need to find the like. Therefore, we need to add a find_like method.

def find_like
@like = @post.likes.find(params[:id])
end

And make sure this method is called on the destroy method. Put this at the top of the controller:

before_action :find_like, only: [:destroy]

The only thing to do now is add an unlike button and make sure it shows up if you click like:

<% pre_like = @post.likes.find { |like| like.user_id == current_user.id} %>
<% if pre_like %>
<%= button_to 'Unlike', post_like_path(@post, pre_like), method: :delete %>
<% else %>
<%= button_to 'Like', post_likes_path(@post), method: :post %>
<% end %>

I first start with finding the like with the user id. If there is one I show the Unlike button and if not, I render the like button. When the user clicks delete, I pass in the post and the like, which it finds using find_post and find_like and then destroys the like.

And you’re done!

--

--

George
Full$taxx

Software developer (in training). In the Makers Academy February 2018 cohort.