1
0

More than 1 year has passed since last update.

【Rails】フォロー・フォロワー機能

Posted at

開発環境

Rails 6.1.4
ruby 2.6.3

前提条件

  • devise導入

目次

  • モデルの作成
  • アソシエーション
  • メソッドの作成
  • コントローラー作成
  • ルーティング
  • View作成

モデルの作成

まずはRelationshipモデルを作成します。
RelationshipモデルはUserモデルの中間テーブルにあたります。
なぜなら、フォローするのもフォローされるのもユーザーで、多 対 多の状態になるからです。

カラムは、下記の通り定義します。

follower_id : フォローしたユーザー
followed_id : フォローされたユーザー

ここでuser_idを使わないということが大切です。
RelationshipモデルはUserモデルの中間テーブルになるため、
どちらもidにはユーザーのidが入ります。
つまり、ここでuser_idを使用してしまうと
判別がつかなくなってしまうため、user_idは使用しません。

それでは、ターミナルでコマンドを実行していきます。

ターミナル
$ rails g model Relationship follower_id:integer followed_id:integer
$ rails db:migrate

これで、Relationshipモデルが完成です。

アソシエーション

中間テーブルは、このアソシエーションのが1番の難所です。
まず、関係性を整理します。

1人のユーザーはたくさんのユーザーをフォローできる(1:N)
1人のユーザーはたくさんのユーザーにフォローされる(1:N)

relationshipモデル

1人のユーザーはたくさんのユーザーをフォローでき、フォローもされるます。
つまり、belongs_toで定義します。

searchesコントローラーのsearchアクションを定義します

models/relationship.rb
class Relationship < ApplicationRecord
  # class_name: "User"でUserモデルを参照
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "User"
end

あれ、belongs_to :userじゃないの??と思いますよね。

そうなんです。
本来、フォローしたユーザーとフォローされたユーザーは同じUserモデルから持ってきたいのですが、belongs_to :userとしてしまうと、どっちがどっちのuserかわからなくなるので、followerfollowedで分けているんです。

ただ、フォローするユーザーとフォローされるユーザーはUserモデルから
持ってきたいので、"User"でUserモデルを参照してね、と定義します。

userモデル

User側のアソシエーションを定義しましょう。

models/user.rb
# フォローをした、されたの関係
has_many :relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy
has_many :reverse_of_relationships, class_name: "Relationship", foreign_key: "followed_id", dependent: :destroy

# 一覧画面で使用
has_many :followings, through: :relationships, source: :followed
has_many :followers, through: :reverse_of_relationships, source: :follower

フォローをした、されたの関係から見ていきましょう。

ここでは、relationshipsreverse_of_relationshipsがありますが、
さきほどと同じ考え方で、わかりにくいため名前をつけています。
class_name: "Relationship"でRelationshipテーブルを参照します。

foreign_key(外部キー)で参照するカラムを指定しています。

次に、フォロー・フォロワーの一覧画面で、user.followersという記述で
フォロワーを表示したいので、throughでスルーするテーブル、
sourceで参照するカラムを指定します。

上の例では、reverse_of_relationshipsテーブルから
follower_idのデータを参照します。

メソッドの作成

モデルにメソッドを定義します。

models/user.rb
# フォローしたときの処理
def follow(user_id)
  relationships.create(followed_id: user_id)
end
# フォローを外すときの処理
def unfollow(user_id)
  relationships.find_by(followed_id: user_id).destroy
end
# フォローしているか判定
def following?(user)
  followings.include?(user)
end

コントローラー作成

relationshipsコントローラを作成します。

ターミナル
$ rails g controller relationships followings followers

relationdhipsコントローラーに、createとdestroyアクションを追加します。
追加したら先ほどのメソッドを使って、コントローラーに記述します。

controllers/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
  # フォロー 一覧
  def followings
    user = User.find(params[:user_id])
    @users = user.followings
  end
  # フォロワー 一覧
  def followers
    user = User.find(params[:user_id])
    @users = user.followers

ルーティング

ルーティングも設定します。

book.rb
# ネストさせる
  resources :users do
    resource :relationships, only: [:create, :destroy]
    get 'followings' => 'relationships#followings', as: 'followings'
    get 'followers' => 'relationships#followers', as: 'followers'
  end

Viewの作成

フォローボタン

フォローボタンを設定したい箇所に配置してください。

任意の場所
<% if current_user.following?(user) %>
  <%= link_to "フォロー外す", user_relationships_path(user.id), method: :delete %>
<% else %>
  <%= link_to "フォローする", user_relationships_path(user.id), method: :post %>
<% end %>

フォロー・フォロワー一覧画面

フォロー一覧もフォロワー一覧も同じ内容を表示するので、部分テンプレートを作成します。

views/relationships/_follow_list.html.erb
<% if users.exists? %>
  <% users.each do |user| %>
    <table>
      <thead>
        <tr>
          <th>name</th>
          <th></th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><%= user.name %></td>
          <td>フォロー数: <%= user.followings.count %></td>
          <td>フォロワー数: <%= user.followers.count %></td>
        </tr>
      </tbody>
    </table>
  <% end %>
<% else %>
  <p>ユーザーはいません</p>
<% end %>

このテンプレートをrenderで呼び出せばOKです!

これで完成です!お疲れ様でした!
あくまで備忘録なので足りない説明等多々あるかと思います。
行き詰まった際の助けになれば幸いです。

1
0
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
0