[Rails] About implementation of like function

Background

I am a beginner with 3 months of programming experience. When I created my personal app, I introduced a ** like function using asynchronous communication **, but I implemented it using the googled one as it is, so I will organize my mind ( I thought I'd post an article to deepen my understanding.

In addition, this article will be written on the assumption that a gem called Devise is installed when implementing this function.

Implementation

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

migration

Create a migration of the Like model.

db/migrate/○○_create_likes.rb


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 ** association foreign keys **.

model

We will 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 like multiple ** and ** Posts can also be liked **, so Both are associated 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 ** If you do 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 gets what the currently logged-in user ** likes ** by association and I'm looking for a ** post (@post) ** to unlike.

View

Creating a partial template

This time, the like button and the display part of the number of likes will be prepared with a partial template. You can understand the reason by looking at 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 already like **, it returns true **, and if you haven't liked it yet, it returns false **.

** "remote: true do" is an option for asynchronous communication **. ** Originally, the page will move to the link destination **, but if you write "remote: true do", ** JS will be searched instead **. Therefore, ** page movement is stopped **. (Since the value seems to jump to the link destination, the page does not move, but it seems that it will be registered in the DB.)

Partial template call

○○.haml



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

Please include this when calling the partial template prepared in the previous section. It is a miso that the id is described by ** 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 have exactly the same description. ** It seems to be considered as JS when using the "j" method **. Someone just stopped pagination and was looking for ** JS **. ..

When you press the like button, the contents of [** like_ <% = @ post.id%> "**] will be rendered ** to the ** partial template you set earlier.

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

Summary

Thank you for reading to the end. Perhaps it's not difficult for those who are used to it, but it's still very difficult for beginners ... We hope that all beginners who refer to this article will be able to implement it safely!

This time it was difficult and I couldn't afford it, so don't be silly. ..

Recommended Posts

[Rails] About implementation of like function
[Rails] Implementation of like function
[Rails] Asynchronous implementation of like function
[Ruby on rails] Implementation of like function
Implementation of like function (Ajax)
[Rails] Implementation of category function
[Rails] Implementation of tutorial function
[Rails] Implementation of CSV import function
[Rails] Implementation of image preview function
[Rails] Implementation of user withdrawal function
[Rails] Implementation of CSV export function
Implementation of like function in Java
Rails sorting function implementation (displayed in order of number of like)
Rails [For beginners] Implementation of comment function
Implementation of search function
Implementation of pagination function
[Rails] Implementation of search function using gem's ransack
Implementation of Ruby on Rails login function (Session)
[Rails] Implementation of image enlargement function using lightbox2
Rails implementation of ajax removal
Implementation of sequential search function
Implementation of image preview function
Implementation of category pull-down function
About adding a like function
[Rails] Implementation of drag and drop function (with effect)
Implementation of Ruby on Rails login function (devise edition)
[Rails] Implementation of multi-layer category function using ancestry "Preparation"
[Rails] Implementation of multi-layer category function using ancestry "seed"
[Rails] Implementation of user logic deletion
[Rails] Implementation of multi-layer category function using ancestry "Editing form"
About Rails 6
[Rails] Implementation of multi-layer category function using ancestry "Creation form"
About error handling of comment function
A note about the seed function of Ruby on Rails
[Rails] Implementation of many-to-many category functions
[Rails] gem ancestry category function implementation
[Ruby on Rails] Comment function implementation
[Rails] Comment function implementation procedure memo
[Rails] Implementation of new registration function in wizard format using devise
I tried to implement Ajax processing of like function in Rails
[Rails] [jQuery] Asynchronous like function implementation using remote: true and js.erb
[Rails] Implementation of coupon function (with automatic deletion function using batch processing)
[Rails] Implementation of tag function using acts-as-taggable-on and tag input completion function using tag-it
[Rails] Addition of Ruby On Rails comment function
Implementation of user authentication function using devise (2)
Rails Addition of easy and easy login function
[Rails 6.0] About batch saving of multiple records
[Ruby on Rails] Follow function implementation: Bidirectional
Implementation of user authentication function using devise (1)
Rails Basic CRUD function implementation procedure scaffold
Implementation of user authentication function using devise (3)
[Rails] Implementation of validation that maintains uniqueness
About Rails routing
DM function implementation
[Rails] I will explain the implementation procedure of the follow function using form_with.
[Rails] Category function
Rails follow function
[Rails] About ActiveJob ,!
About Rails controller
[Rails] Notification function
[JQuery] Implementation procedure of AutoComplete function [Java / Spring]