LoginSignup
1
3

More than 3 years have passed since last update.

[Rails]フォロー機能実装について

Last updated at Posted at 2020-11-24

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
create_relationship.rb
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 

② モデルの関連付け

relationship.rb
class Relationship < ApplicationRecord

  belongs_to :follwer, class_name: "User"
  belongs_to :follwed, class_name: "User"

end

ここの書き方は単純。
先ほど設定した「follower_id」と「followed_id」の値からUsersテーブルのレコードを参照する。
ただ、「class_name: 'モデル名'」で参照するモデルを指定しなければいけないことに注意。

続いてUserモデルを記述していく。
ここが個人的に一番混乱した。

user.rb

  # フォローするユーザ
  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モデル。

user.rb
  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

④ フォローボタン作成、コントローラを記述

続いてコントローラ

relationships_controller.rb
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ファイルにフォローボタンを作成する

users/show.html.erb
  <% 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をフォローしている

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

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3