This article is a continuation of this article.
▼ Previous article Implement user follow function in Rails (I use Ajax) ①
Carrying out Rails challenges. We have decided to implement the follow function of User.
In the previous articles, we have created the migration file and defined the association to the model file, so this time we will add controller, view, and ** model method **.
The execution environment is as follows.
Rails 5.2.3Ruby 2.6.0The goal this time is like this. When you press the button, the follow / unfollow button will appear asynchronously with the crispness.
The usage of this function is as follows.
--Users can follow other users --You cannot follow the same user twice --Users cannot follow themselves
To find out why this happens, read Last article: relaxed:
First, we will implement it in a non-asynchronous manner.
I will write both controller and model lightly, so if you want to know more, you may want to read the article around here.
-Create a "Like" function with Rails-② Create action for "Like" -Create a "Like" function in Rails-③ Enable to cancel "Like" -Implement the "Like" function in Ajax in Rails.
controller
The description of controller is as follows.
relationships_controller.rb
class RelationshipsController < ApplicationController
  def create
    @other_user = User.find(params[:follower])
    current_user.follow(@other_user)
  end
  def destroy
    @user = current_user.relationships.find(params[:id]).follower
    current_user.unfollow(params[:id])
  end
end
follow and unfollow are model methods. I will explain later.
view
The description of the view file is as follows. The class for decoration is omitted. It is assumed that the variable representing user (each user) is passed from outside the code displayed here.
view
- if logged_in? && current_user != user
  - if current_user.following?(user)
    = button_to 'Unfollow', relationship_path(current_user.relationships.find_by(follower: user)), method: :delete
  - else
    = button_to 'Follow', relationships_path(follower: user)
following? Is also a model method.
model
Define follow, unfollow, and following? Methods as model methods for the user model, respectively.
python
class User < ApplicationRecord
  #The part defined in the previous article
  has_many :relationships, dependent: :destroy
  has_many :followings, through: :relationships, source: :follower
  has_many :passive_relationships, class_name: 'Relationship', foreign_key: 'follower_id', dependent: :destroy
  has_many :followers, through: :passive_relationships, source: :user
  #Model method added this time
  def follow(other_user)
    return if self == other_user
    relationships.find_or_create_by!(follower: other_user)
  end
  def following?(user)
    followings.include?(user)
  end
  def unfollow(relathinoship_id)
    relationships.find(relathinoship_id).destroy!
  end
end
Above this class is Complex Associations as appropriate in the previous article.
At this point, the non-Ajax follow function is complete. Since the screen is transitioned with redirect_to for the demo, it looks a bit asynchronous, but after pressing the" Follow "button and reloading the screen, the" Unfollow "button appears.
Now let's make this an asynchronous communication. This is also written lightly, so if you are wondering why this happens, please see this article.
remote: true to POST ajax posts.
First, cut out the button part partially with the remote: true option.
ruby:views/relationships/_follow_button.html.slim
= button_to 'Follow', relationships_path(follower: user), remote: true
ruby:views/relationships/_unfollow_button.html.slim
= button_to 'Unfollow', relationship_path(current_user.relationships.find_by(follower: user)), method: :delete, remote: true
#View file that originally had a button
- if logged_in? && current_user != user
 div id="follow-button-#{user.id}"
   - if current_user.following?(user)
      = render 'relationships/unfollow_button', user: user
   - else
      = render 'relationships/follow_button', user: user
**. Js.erb fileThe file of the part to be called dynamically is written to the **. Js.erb file.
erb:views/relationships/create.js.erb
$("#follow-button-<%= @other_user.id %>").html("<%= j(render 'unfollow_button', user: @other_user) %>")
erb:views/relationships/destroy.js.erb
$("#follow-button-<%= @user.id %>").html("<%= j(render 'follow_button', user: @user) %>")
It's done here ^^ All you have to do to make Ajax is rewrite the view file: relaxed: Simple: sparkles:
The follow / unfollow function has a data structure of 80%! The design of the DB and model is complicated, isn't it? I'm glad I read it well ^^
Recommended Posts