自分用にまとめます。
実装
モデル作成
$ rails g model Relationship follower_id:integer followed_id:integer
$ rails db:migrate
マイグレーションファイル
20200723070930_create_relationships.rb
class CreateRelationships < ActiveRecord::Migration[5.2]
def change
create_table :relationships do |t|
t.integer :follower_id, null: false
t.integer :followed_id, null: false
t.timestamps
end
end
end
relationship.rb
class Relationship < ApplicationRecord
# フォローするユーザー
belongs_to :follower, class_name: 'User'
# フォローされるユーザー
belongs_to :followed, class_name: 'User'
validates :follower_id, presence: true
validates :following_id, presence: true
end
class_name: 'User':「followerもfollowedもUserにいるよ」という意味
app/models/user.rb
class User < ApplicationRecord
# フォロー取得
has_many :follower, class_name: 'Relationship', foreign_key: 'follower_id', dependent: :destroy
# フォロワー取得
has_many :followed, class_name: 'Relationship', foreign_key: 'followed_id', dependent: :destroy
# 自分がフォローしている人
has_many :following_user, through: :follower, source: :followed
# 自分をフォローしている人(フォロワー)
has_many :follower_user, through: :followed, source: :follower
# ユーザーをフォローする
def follow(user_id)
follower.create(followed_id: user_id)
end
# ユーザーのフォローを外す
def unfollow(user_id)
follower.find_by(followed_id: user_id).destroy
end
# フォロー確認を行う
def following?(user)
following_user.include?(user)
end
end
コントローラ作成
$ rails g controller relationships
config/routes.rb
Rails.application.routes.draw do
post 'follow/:id', to: 'relationships#follow', as: 'follow'
post 'unfollow/:id', to: 'relationships#unfollow', as: 'unfollow'
get 'users/following/:user_id', to: 'users#following', as: 'users_following'
get 'users/follower/:user_id', to: 'users#follower', as: 'users_follower'
end
users_controller.rb
class UsersController < ApplicationController
# @userがフォローしているユーザー一覧
def following
@user = User.find(params[:user_id])
@followings = @user.following_user
end
# @userをフォローしているユーザー一覧
def follower
@user = User.find(params[:user_id])
@followers = @user.follower_user
end
end
relationship_controller.rb
class RelationshipsController < ApplicationController
# フォローする
def follow
@user = User.find(params[:id])
current_user.follow(params[:id])
render :create
end
# アンフォローする
def unfollow
@user = User.find(params[:id])
current_user.unfollow(params[:id])
render :destroy
end
end
renderでcreate.js.erbとdestroy.js.erb呼び出すことで、
ページ遷移なしでフォロー・解除が行えるようになる。
users/show.html.slim
# create.js.erbとdestroy.js.erbで書き換えるため記述必須
div id="follow_form"
# フォローボタン部分をパーシャルで飛ばす
= render 'relationships/follow', user: @user
_follow.html.slimファイルをrelationshipsディレクトリ配下に手動で作成
パーシャルで飛ばしたフォローボタン部分の記述を貼り付ける。
relationships/_follow.html.slim
- unless user == current_user
- if current_user.following?(user)
# jsファイルを呼び出すためにremote: trueを追記
= link_to unfollow_path(user), method: :post, remote: true, class: 'btn btn-outline-info m-0 btn-sm' do
i.fas.fa-user フォロー中
- else
# jsファイルを呼び出すためにremote: trueを追記
= link_to follow_path(user), method: :post, remote: true, class: 'btn btn-outline-success m-0 btn-sm' do
i.far.fa-user フォローする
create.js.erbファイルをrelationshipsディレクトリ配下に手動で作成
relationships/create.js.erb
# id="follow_form"部分を_follow.html.slimの内容にページ遷移なしで書き換える
$('#follow_form').html("<%= j(render 'relationships/follow',{ user: @user }) %>");
destroy.js.erbファイルをrelationshipsディレクトリ配下に手動で作成
relationships/destroy.js.erb
# id="follow_form"部分を_follow.html.slimの内容にページ遷移なしで書き換える
$('#follow_form').html("<%= j(render 'relationships/follow',{ user: @user }) %>");
完成!