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をフォローしている
初めてフォロー機能に触れた時、「する」「される」の関係がわからなくなり、アソシエーションの中身がぐちゃぐちゃになっていた。解決するのにだいぶ時間を使ってしまった。
モデルの名義やそもそものやり方は人それぞれなので、自分が理解できるやり方を見つけるのが一番だと感じた。