Rails フォロー機能
フォロー・フォロワー機能の追加
実装する機能
コントローラ
- relationshipsコントローラを追加
- createアクションを追加(用途:フォローを作成)
- destroyアクションを追加(用途:フォローを削除)
- フォローする・外すボタンをクリックしたら元画面に遷移すること
モデル
- relationshipモデルを作成
ビュー
- サイドバーにフォロー数・フォロワー数を表示
- マイページ以外のサイドバーにフォローする・外すボタンを追加
- ユーザー一覧画面にフォロー数・フォロワー数・フォローする・外すボタンの設置
- フォロー・フォロワー一覧画面を作成すること
手順
- モデルの作成
- アソシエーション
- メソッド作成
- コントローラー
- ビュー
モデルの作成
フォロー機能の場合、フォローするのもされるのもユーザであるため、
少なくとも片方は、user_id以外のカラム名にする必要がある。
relationshipsテーブルに、以下カラムを作成!
カラム名 | データ型 | 説明 |
---|---|---|
id | (初期カラム) | 主キー (PK) |
follower_id | integer | フォローするユーザのid |
followed_id | integer | フォローされるユーザのid |
普通、外部キーとテーブル名は一致していないといけないので
各テーブルをfollowerテーブルとfollowerdテーブルにする。
rails g model Relationship follower_id:integer followed_id:integer
rails db:migrateも忘れずに!
アソシエーション
models/relationship.rb
class Relationship < ApplicationRecord
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
end
belongs_to :userとすると、どっちがどっちのuserかわからなくなるので、followerとfollowedで分けている。
また、class_nameがないと、followerテーブルとfollowedテーブルを探しに行ってしまうので、class_name: "User"でuserテーブルからデータをとってきてもらうようにしている。
class_nameとは
関連名と参照先のクラス名を異なるものに置き換えることができるオプション。
モデル名を直接指定できる。
関連付けの相手となるオブジェクト名を関連付け名から生成できない事情がある場合に役立つ!
models/user.rb
class User < ApplicationRecord
# フォローをした、されたの関係
has_many :followers, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy
has_many :followeds, class_name: "Relationship", foreign_key: "followed_id", dependent: :destroy
# 一覧画面で使う
has_many :following_users, through: :followers, source: :followed
has_many :follower_users, through: :followeds, source: :follower
end
まずは、フォローをした、されたの関係から!
先ほどと同じ考えでfollower、followedと名前をつけている。
class_name: "Relationship"でRelationshipテーブルを参照。
foreign_keyで参照するカラムを指定している。
次に、フォロー・フォロワーの一覧画面(foreign_keyで繋いだところの定義)
following_user:中間テーブルを通し、followerモデルのフォローされる側を取得
follower_user:中間テーブルを通し、followedモデルのフォローする側を取得
メソッド作成
モデルにメソッドを記述していく。
これで、コントローラーをすっきりできる🙌🏻
# フォローしたときの処理
def follow(user_id)
followers.create(followed_id: user_id)
end
# フォローを外すときの処理
def unfollow(user_id)
followers.find_by(followed_id: user_id).destroy
end
#フォローしていればtrueを返す
def following?(user)
following_users.include?(user)
end
ルーティングの設定
Userと、Relationshipは関連づけられているためuserのidが必要。
relationshipsをネストする。
resources :users, only: [:index, :show, :edit, :update] do
member do
get :follows, :followers
end
resource :relationships, only: [:create, :destroy]
end
userのidを含んだ形で、個々のリソースに対してfollowsアクションとfollowersアクションが設定できた!
memberとは
resourcesで生成されるルートに、決められたルート以外のルートを追加するための処理!
resourcesのブロック(doとend)の中で使います。
ルートを生成したときに:id をつけたくない場合はcollectionメソッドを使う。
コントローラー
rails g controller relationships
relationships_controller
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
users_controller
# フォロー一覧
def follows
user = User.find(params[:id])
@users = user.following_users
end
# フォロワー一覧
def followers
user = User.find(params[:id])
@user = user.follower_users
end
ユーザー詳細ページで、フォロー数とフォロワー数を表示するための記述
def show
@user = User.find(params[:id])
@following_users = @user.following_users
@follower_users = @user.follower_users
end
ビュー
まずこの部分を作成!
user_infoの部分テンプレートに追記しました!
<th>Follows</th>
<td>
<%= link_to follows_user_path(user) do %>
<h6><%= user.followers.count %></h6>
<% end %>
</td>
</tr>
<tr>
<th>Followers</th>
<td>
<%= link_to followers_user_path(user) do %>
<h6><%= user.followeds.count %></h6>
<% end %>
</td>
</tr>
<tr>
<td>
<% if current_user != user %>
<% if current_user.following?(user) %>
<%= link_to "フォロー外す", user_relationships_path(user.id), method: :delete, class: "btn btn-danger" %>
<% else %>
<%= link_to "フォローする", user_relationships_path(user.id), method: :post, class:"btn btn-success" %>
<% end %>
<% end %>
</td>
render部分
<%= render partial: "partial/user_info", locals: { user: current_user }%>
<% if current_user != user %>
この記述で、ログインしているユーザー自身にはフォローボタンが表示されないようにしている。
次にこの部分!
フォロー、フォロワー数を載せたいところに記述!
users/index.html.erb
<td>フォロー<%= user.followers.count %></td>
<td>フォロワー<%= user.followeds.count %></td>
フォローボタンも追加!(部分テンプレートを使用)
renderでcurrent_userを渡した。
<td><%= render partial: "relationships/follow_btn", locals: { user: current_user } %></td>
relationships/_follow_btn
<% if current_user.following?(user) %>
<%= link_to "フォロー外す", user_relationships_path(user.id), method: :delete, class: "btn btn-danger" %>
<% else %>
<%= link_to "フォローする", user_relationships_path(user.id), method: :post, class:"btn btn-success" %>
<% end %>
次にフォロー・フォロワー一覧画面も作成!
view/users配下にfollows.html.erbとfollowers.html.erbを作成!
follows.html.erb
<h2>Follows</h2>
<table class='table'>
<thead>
<tr>
<th>Image</th>
<th>name</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<% @users.each do |user| %>
<tr>
<td>
<%= link_to user_path(user) do %>
<%= image_tag user.get_profile_image(50,50) %>
<% end %>
</td>
<td><%= user.name %></td>
<td>
<%= link_to follows_user_path(user) do %>
<h6>フォロー<%= user.followers.count %></h6>
<% end %>
</td>
<td>
<%= link_to followers_user_path(user) do %>
<h6>フォロワー<%= user.followeds.count %></h6>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
followers.html.erb
<h2>Followers</h2>
<table class='table'>
<thead>
<tr>
<th>Image</th>
<th>name</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<% @user.each do |user| %>
<tr>
<td>
<%= link_to user_path(user) do %>
<%= image_tag user.get_profile_image(50,50) %>
<% end %>
</td>
<td><%= user.name %></td>
<td>
<%= link_to follows_user_path(user) do %>
<p>フォロー<%= user.followers.count %></p>
<% end %>
</td>
<td>
<%= link_to followers_user_path(user) do %>
<p>フォロワー<%= user.followeds.count %></p>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
users_controllerのこの部分!
eachに入れるインスタンス変数をそれぞれ入れる。
def follows
user = User.find(params[:id])
@users = user.following_users
end
def followers
user = User.find(params[:id])
@user = user.follower_users
end
完成!
参照
復習で2回目の実装!
前より理解しながら進められた🙆🏻♀️
Discussion