Railsでのフォロー機能実装に手間取ったので、
自分が理解した範囲で手順を書いていく。
※プログラミング初心者のため、内容に不備や間違っている箇所があるかもしれません。
自分用のメモとして残していますが、もし不備等あればご指摘いただければと思います。
###開発環境###
Ruby 2.6.3
Rails 5.2.4
###前提機能###
ログイン機能(devise)
###実装の流れ###
① 中間テーブルを作成する
② Userモデル同士を参照するアソシエーションを記述する
③ follow、unfollowメソッドを定義する
④ フォローボタンを作成、コントローラを記述する
##① 中間テーブルを作成する
「フォローするユーザ」と「フォローされるユーザ」を取得する際、
どちらも同じUserモデルを参照するため中間テーブルが必要になる。
中間テーブルについてはこちらの記事が大変わかりやすく、参考にさせていただいた。
https://qiita.com/morikuma709/items/1e389ddcdfc1102ef3f4
まず、Relationshipモデルを作成
$ rails g model Relationship
class CreateRelationships < ActiveRecord::Migration[5.2]
def change
create_table :relationships do |t|
t.references :follower, foreign_key: true
t.references :followed, foreign_key: true
t.timestamps
t.index [:follower_id, :followed_id], unique: true
end
end
end
カラムには「follower_id(フォローするユーザ)」と「followed_id(フォローされるユーザ)」を設定する。
どちらもUserモデルにて外部キーとして使用する(後述)のでreferencesで定義。
migrateを忘れずに。
$ rails db:migrate
##② モデルの関連付け###
class Relationship < ApplicationRecord
belongs_to :follwer, class_name: "User"
belongs_to :follwed, class_name: "User"
end
ここの書き方は単純。
先ほど設定した「follower_id」と「followed_id」の値からUsersテーブルのレコードを参照する。
ただ、「class_name: 'モデル名'」で参照するモデルを指定しなければいけないことに注意。
続いてUserモデルを記述していく。
ここが個人的に一番混乱した。
# フォローするユーザ
has_many :active_relationships, class_name: "Relationship",
foreign_key: "follower_id",
dependent: :destroy
# 自分がフォローしているユーザ
has_many :followed_users, through: :active_relationships,
source: :followed
# フォローされるユーザ
has_many :passive_relationships, class_name: "Relationship",
foreign_key: "followed_id",
dependent: :destroy
# 自分をフォローしているユーザ
has_many :following_users, through: :passive_relationships,
source: :follower
has_manyに続くモデル名は新たに作成したもの。もちろんモデル自体は存在しない。
・フォローするユーザとフォローされるユーザを取得
今回はそれぞれ、「active_relationships」と「passive_relationships」とした。
→active_relationshipsの場合
参照するモデルはRelationshipモデル(class_name: "Relationship")
さらに、値を参照するカラムは「follower_id」(foreign_key: "follower_id")
・自分がフォローしているユーザと自分をフォローしているユーザ
こちらは「followed_users」と「following_users」とした。
→followed_usersの場合
active_relationshipsユーザーからフォローされているユーザ
active_relationshipsを参照(through: :passive_relationships)
取得する値は「followed_id」(source: :followed)
##③ メソッドを定義する ##
Relationshipsコントローラのアクション内で使用するメソッドを定義する。
場所はUserモデル。
def follow(user_id)
active_relationships.create(followed_id: user_id)
end
def unfollow(user_id)
active_relationships.find_by(followed_id: user_id).destroy
end
def following?(user)
followed_users.include?(user)
end
##④ フォローボタン作成、コントローラを記述##
続いてコントローラ
class RelationshipsController < ApplicationController
def create
current_user.follow(params[:user_id])
redirect_to request.referer
end
def destroy
current_user.unfollow(params[:user_id])
redirect_to request.referer
end
end
viewファイルにフォローボタンを作成する
<% if current_user.following?(@user) %>
<%= link_to 'フォロー中', user_relationship_path(@user), method: :delete, class:"btn" %>
<% else %>
<%= link_to 'フォローする', user_relationships_path(@user), method: :post, class:"btn" %>
<% end %>
@userにはparams[:id]が格納されている。
current_user.following?(@user)で@userがfollowed_usersに含まれているかを判断する。
以上でフォロー機能の実装は完了。
時間がある時に一覧ページ作成の流れも追記しようと思う。
####自分がたどり着いた考え方まとめ####
active_relationships = フォローするユーザ
followed_users = active_relationshipsにフォローされているユーザ
passive_relationships = フォローされるユーザ
following_users = active_relationshipsをフォローしている
初めてフォロー機能に触れた時、「する」「される」の関係がわからなくなり、アソシエーションの中身がぐちゃぐちゃになっていた。解決するのにだいぶ時間を使ってしまった。
モデルの名義やそもそものやり方は人それぞれなので、自分が理解できるやり方を見つけるのが一番だと感じた。