[Java] [Rails] Implementation of the like function

3 minute read

History

I am a beginner with 3 months programming history. When I created a personal application, I introduced a like feature that uses asynchronous communication, but since I implemented it using what I googled, I keep my mind organized ( I decided to post an article for better understanding).

In addition, this article will be written assuming that a gem called Devise is installed in order to implement this function.

Implementation

This time, we will use the User model, Posts model, and Likes model.

Migration

Create a migration for the Like model.

class CreateLikes <ActiveRecord::Migration[5.0]
  def change
    create_table :likes do |t|
      t.references :post, foreign_key: true
      t.references :user, foreign_key: true
      t.timestamps
    end
  end
end

Both user_id and post_id are set as foreign key of association.

model

Set the association for each model.

models/user.rb


  has_many :posts
  has_many :likes

models/post.rb


  belongs_to :user
  has_many :likes

models/like.rb


  belongs_to :user
  belongs_to :post

Users can have multiple likes, You can also like multiple posts, so Both will associate with like with has_many.

root

config/routes.rb


Rails.application.routes.draw do
  devise_for :users

  resources :users
  resources :posts do
    resources :likes, only: [:create, :destroy]
  end
end

Nest likes in posts. Nesting allows you to determine which post has a like.

For reference Rails routes…

terminal


post_likes POST /posts/:post_id/likes(.:format) likes#create
 post_like DELETE /posts/:post_id/likes/:id(.:format) likes#destroy

You can see that like is called in association with a specific post.

Controller

controllers/likes_controller.rb


class LikesController <ApplicationController
  before_action :set_post

  def create
    @like = Like.create(user_id: current_user.id, post_id: @post.id)
  end

  def destroy
    @like = current_user.likes.find_by(post_id: @post.id)
    @like.destroy
  end

  private
  def set_post
    @post = Post.find(params[:post_id])
  end
end

destroy destroys the current login user **likes by the association, I’m looking for a post (@post) that I want to unlike.

Views

Creating a partial template

This time, I will prepare a part template for the like button and the display part of the number of likes. You can understand the reason by seeing the explanation of JavaScript in the next section.

haml:view/likes/_like.html.haml


- if Like.find_by(user_id: current_user.id, post_id: @post.id)
  = link_to "/posts/#{@post.id}/likes/#{@post.likes.ids}", method: :delete, class:"element", remote: true do
    = icon("fas", "heart", class: "like")
- else
  = link_to "/posts/#{@post.id}/likes", method: :post, class:"element", remote: true do
    = icon("fas", "heart", class: "unlike")
.count
  = @post.likes.length

If you have already liked it, it will return true, and if you have not liked it yet, it will return false.

“Remote: true do” is an option for asynchronous communication. Originally the page moves to the link destination, but if you enter “remote: true do”, JS will be searched instead. Therefore, page movement will be stopped. (The page does not move because the value jumps to the link destination, but it seems to be registered in the DB.)

*Font-awesome-sassisrequiredtouse”icon(“fas”,”heart”)”. *This time, css is not described.

Partial template call


# like{ id: @post.id}
  = render "likes/like"

Please include this description when calling the partial template prepared in the previous section. It is miso that the id is described as custom data attribute.

JavaScript

This is the key to asynchronous communication.

javascript:views/likes/create.js.erb


$("#like_<%= @post.id %>").html("<%= j(render'likes/like') %>");

javascript:views/likes/destroy.js.erb


$("#like_<%= @post.id %>").html("<%= j(render'likes/like') %>");

Both are exactly the same. Using the “j” method seems to be considered JS. A while ago, someone stopped moving pages and was looking for JS. ..

When you click the like button, the contents of [like_<%= @post.id %>”] will be rendered** into the **partial template that you set earlier.

In other words, it will be updated asynchronously to the “posts/like” of the partial template without updating the page.

Summary

Thank you for reading to the end. Perhaps it shouldn’t be difficult for those who are used to it, but it is very difficult for beginners… I pray that all the beginners who refer to this article can implement it safely!

This time it was difficult and I couldn’t afford it, so don’t play around. ..