開発環境
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アクションを定義します
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かわからなくなるので、follower
とfollowed
で分けているんです。
ただ、フォローするユーザーとフォローされるユーザーはUserモデルから
持ってきたいので、"User"
でUserモデルを参照してね、と定義します。
userモデル
User側のアソシエーションを定義しましょう。
# フォローをした、されたの関係
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
フォローをした、されたの関係から見ていきましょう。
ここでは、relationships
とreverse_of_relationships
がありますが、
さきほどと同じ考え方で、わかりにくいため名前をつけています。
class_name: "Relationship"
でRelationshipテーブルを参照します。
foreign_key(外部キー)
で参照するカラムを指定しています。
次に、フォロー・フォロワーの一覧画面で、user.followers
という記述で
フォロワーを表示したいので、through
でスルーするテーブル、
source
で参照するカラムを指定します。
上の例では、reverse_of_relationships
テーブルから
follower_id
のデータを参照します。
メソッドの作成
モデルにメソッドを定義します。
# フォローしたときの処理
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アクションを追加します。
追加したら先ほどのメソッドを使って、コントローラーに記述します。
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
ルーティング
ルーティングも設定します。
# ネストさせる
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 %>
フォロー・フォロワー一覧画面
フォロー一覧もフォロワー一覧も同じ内容を表示するので、部分テンプレートを作成します。
<% 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です!
これで完成です!お疲れ様でした!
あくまで備忘録なので足りない説明等多々あるかと思います。
行き詰まった際の助けになれば幸いです。