フォロー機能の実装
1.目的
自分の気に入った人をフォローしたりフォローされたりできるようにする。
2.扱うgem・API
なし
3.ER図
4.手順
①relationshipモデルの作成を行います。
terminalで以下のコマンドを実行します。
% rails g model Relationship
②作成されたマイグレーションファイルを以下のように編集します。
class CreateRelationships < ActiveRecord::Migration[6.0]
def change
create_table :relationships do |t|
t.integer :follower_id, null: false
t.integer :following_id, null: false
t.timestamps
end
add_index :relationships, :follower_id
add_index :relationships, :following_id
add_index :relationships, %i[follower_id following_id], unique: true
end
end
add_index :relationships, %i[follower_id following_id], unique: true
は、一度フォローしたユーザーを二度フォローしてしまわないようにするための一意の設定です。
relationshipsテーブルのfollower_id、following_idカラムにindexを貼ることでアルファベット順にfollower_id、following_idを並べ替え検索しやすいようにしてくれます。
③アソシエーションを定義します。
フォローするのとフォローされるのとで能動的関係と受動的関係で分けることをします。
ここでは、能動的関係をfollwerと呼び、受動的関係をfollowingと呼ぶことにしています。
○フォローすることを考えてやっていきます。
能動的関係であるfollwerからやっていきます。
まずあるユーザーA がユーザーBをフォローすることを考えます。
ユーザーAからフォローはたくさんでき、フォローされた側からはAさんしかいないので1対多の関係です。
ユーザーAは、follwersモデルを通してフォローを行います。
user.rbに以下を追記します。
has_many :followers,
class_name: 'Relationship',
foreign_key: 'follower_id',
dependent: :destroy,
inverse_of: :follower
今回はAさんがfollwingしようとしているので、Aさんがrelationshipsテーブルにfollwing_idを登録しています。
has_many :followersだと、railsが外部キーにfollers_idを探してしまい、できないので外部キーを明示的に示す必要があります。Bさんが今回は、follwer_idを登録する役割を持っています。
relationsip.rbに以下を記します。
class Relationship < ApplicationRecord
belongs_to :follower, class_name: 'User'
end
○フォローされることのみを考えてやっていきます。
この際、relationshipモデルをfollwingモデルとして置き換えます。
ユーザーAをフォローしている人は、たくさんいるのでhas_many
ユーザーAをフォローしている人にとってfollwingの対象は1人であるのでbelongs_to です。
relationship.rbに以下を追記します。
belongs_to :following, class_name: "User"
user.rbに以下を追記します。
has_many :followings,
class_name: 'Relationship',
foreign_key: 'following_id',
dependent: :destroy,
inverse_of: :following
フォローされているユーザーAをfollwing_idを外部キーとして特定しています。
○フォローしているユーザーの集団を取り出します。
1人のユーザーにはたくさんの「フォローする/フォローされる」の多対多のリレーションがあります。
user.rbに以下を追記します。
has_many :following_users, through: :followers, source: :following
中間テーブルにfollwersテーブルを指定しています。その結果、user.following_users と打つだけで、userが中間テーブルfollers を取得し、その1つ1つのfollowing_idから、「フォローしているUser達」を取得できるようになります。
source: :followingはわかりやすくするためのものであるのでなくてもOK!!
○あるユーザーをフォローしているフォロワーを取り出します。
user.rbに以下の内容を追記します。
has_many :follower_users, through: :followings, source: :follower
これでuser.follower_usersメソッドが使えるようになります。
○取得したデータを簡単に扱うためのメソッドを追記していきます。
user.rbに以下の内容を追記します。
##フォローするときのメソッド
def follow(other_user_id)
followers.create(following_id: other_user_id)
end
##フォローしているのか確認のメソッド
def following?(other_user)
following_users.include?(other_user)
end
##フォローを外すときのメソッド
def unfollow(other_user_id)
followers.destroy(following_id: other_user_id)
end
④app/views/users/show.html.erbに以下の内容を追記します。
<div class="follow">
<%= render "follow_form" %>
</div>
⑤app/views/usersディレクトリに_follw_form.html.erbファイルを作成します。
次に_follw_form.html.erbに以下のように編集します。
<%if user_signed_in?%>
<%unless @user == current_user%>
<% if current_user.following?(@user)%>
<%=button_to "フォロー中",relationship_path,method: :delete ,class: "fllowig-btn" %>
<%else%>
<%= form_for(@user.followers.build) do |f| %>
<%= hidden_field_tag :follow_id, @user.id %>
<%= f.submit "フォロー" ,class: "follow-btn" %>
<% end %>
<%end%>
<%end%>
<%end%>
⑥ルーティングの設定を行います。
routes.rbを以下のように追記します。
resources :users, only: [:show, :index, :edit, :update, :destroy] do
member do
get :followings, :followers, :follow_review, :good_review
end
end
どの人をフォローしているのか、誰にフォローされているのか、フォローした人のレビュー表示、いいねしたものの表示のアクションを加える。
⑦users_controller.rbに以下を追記します。
class UsersController < ApplicationController
before_action :set_user, except: [:index]
def followings
@followings = @user.following_users
end
def followers
@followers = @user.follower_users
end
def follow_review
@followings = @user.following_users
end
def good_review
end
private
def set_user
@user = User.find(params[:id])
end
end
⑧app/views/users/show.html.erbに以下の内容を追記します。
<div class="user-item">
<div class="user-nick">
<%="#{@user.nickname}のホーム" %>
</div>
<div class="follow">
<%= render "follow_form" %>
<p class="follow-count">
<%= link_to "#{@user.followers.count} #{User.human_attribute_name("フォロー")}", followings_user_path %> <%= link_to "#{@user.followings.count} #{User.human_attribute_name("フォロワー")}", followers_user_path %>
</p>
</div>
</div>
<div class="user_matome">
<%=link_to "フォローユーザーレビュー",follow_review_user_path ,class:"follow" %>
<%=link_to "いいねしたレビュー", good_review_user_path, class:"good-r" %>
</div>
フォローした人へ遷移、フォローされた人へ遷移、フォローしたユーザーレビューへの遷移、いいねしたレビューへの遷移。
⑨app/views/usersディレクトリ以下にfolloers.html.erb、followings.html.erb、follow_review.html.erb、good_review.html.erbファイルを作成します。
○folloers.html.erbを以下のように編集します。
<%=render "shared/header"%>
<div class='main'>
<div class="follower-list">
<h1>フォロワー</h1>
</div>
<div class='item-contents'>
<h2 class='title'>Pick Up</h2>
<div class="subtitle" >
user list
</div>
<ul class='item-lists'>
<% @followers.each do |user| %>
<div class="comment-profile">
<div class="profile">
<% if user.image.attached? %>
<%= image_tag user.image, class: "user-icon3" %>
<% else %>
<%= image_tag "willy.png", alt: "user-icon", class: "user-icon3" %>
<% end %>
</div>
<div class="name-file">
<%= link_to user.nickname, user_path(user.id) ,class: "message-nickname" %>
</div>
</div>
<%end%>
</ul>
<%= link_to t("button.back"), user_path %>
</div>
</div>
<%=render "shared/footer"%>
○followings.html.erbを以下のように編集します。
<%=render "shared/header"%>
<div class='main'>
<div class="follow-list">
<h1>フォロー中</h1>
</div>
<div class='item-contents'>
<h2 class='title'>Pick Up</h2>
<div class="subtitle" >
user list
</div>
<ul class='item-lists'>
<% @followings.each do |user| %>
<div class="comment-profile">
<div class="profile">
<% if user.image.attached? %>
<%= image_tag user.image, class: "user-icon3" %>
<% else %>
<%= image_tag "willy.png", alt: "user-icon", class: "user-icon3" %>
<% end %>
</div>
<div class="name-file">
<%= link_to user.nickname, user_path(user.id) ,class: "message-nickname" %>
</div>
</div>
<%end%>
</ul>
<%= link_to t("button.back"), user_path %>
</div>
</div>
<%=render "shared/footer"%>
○follow_review.html.erbを以下のように編集します。
<%=render "shared/header"%>
<div class='main'>
<div class="user-item">
<div class="user-nick">
<h1>フォローユーザーレビュー一覧</h1>
</div>
</div>
<div class="user_matome">
<%=link_to "いいねしたレビュー",good_review_user_path ,class:"follow" %>
<%=link_to "#{@user.nickname}のホームへ", user_path, class:"good-r" %>
</div>
<%if user_signed_in? && current_user.id == @user.id%>
<div class="myrank">
</div>
<%end%>
<div class='item-contents'>
<h2 class='title'>Pick Up</h2>
<div class="subtitle" >
follow user review
</div>
<ul class='item-lists'>
<% @followings.each do |user| %>
<%user.items.page(params[:page]).per(16).each do |item|%>
<li class='list'>
<%= link_to item_path(item.id),class:"link" do %>
<div class='item-info'>
<%= item.name%>
</div>
<div class='item-img-content'>
<%if item.image.attached? %>
<%= image_tag item.image, class: "item-img" %>
<%else%>
<%= image_tag 'soundreview2.png', class: "item-img" %>
<%end%>
</div>
<div class="profile-all">
<div class="profile2">
<% if item.user.image.attached? %>
<%=link_to user_path(item.user.id),class:"user-icon4" do %>
<%= image_tag item.user.image, class: "user-icon4" %>
<%end%>
<% else %>
<%=link_to user_path(item.user.id) ,class:"user-icon4" do %>
<%= image_tag "willy.png", alt: "user-icon", class: "user-icon4" %>
<%end%>
<% end %>
</div>
<div class="item-create">
<div class="item-user-name">
<%= link_to item.user.nickname, user_path(item.user.id) %>
</div>
<div class="created_at" >
<%=item.created_at.strftime('%Y/%m/%d')%>
</div>
</div>
<div class="good-county">
<i class="fas fa-thumbs-up"></i> <%=item.likes.count%>
</div>
</div>
<% end %>
</li>
<%end%>
<% end %>
</ul>
</div>
<%= link_to new_item_path, class: 'item-btn' do %>
<span class='item-btn-text'>Post Review</span>
<%= image_tag 'icon_camera.png' , size: '79x50' ,class: "item-btn-icon" %>
<% end %>
</div>
<%= render "shared/footer" %>
○good_review.html.erbを以下のように編集します。
<%=render "shared/header"%>
<div class='main'>
<div class="user-item">
<div class="user-nick">
<h1>マイグッドレビュー一覧</h1>
</div>
</div>
<div class="user_matome">
<%=link_to "フォローユーザーレビュー",follow_review_user_path ,class:"follow" %>
<%=link_to "#{@user.nickname}のホームへ", user_path, class:"good-r" %>
</div>
<%if user_signed_in? && current_user.id == @user.id%>
<div class="myrank">
</div>
<%end%>
<div class='item-contents'>
<h2 class='title'>Pick Up</h2>
<div class="subtitle" >
my good review
</div>
<ul class='item-lists'>
<%@user.like_items.each do |post|%>
<li class='list'>
<%= link_to item_path(post.id),class:"link" do %>
<div class='item-info'>
<%= post.name%>
</div>
<div class='item-img-content'>
<%if post.image.attached? %>
<%= image_tag post.image, class: "item-img" %>
<%else%>
<%= image_tag 'soundreview2.png', class: "item-img" %>
<%end%>
</div>
<div class="profile-all">
<div class="profile2">
<% if post.user.image.attached? %>
<%=link_to user_path(post.user.id),class:"user-icon4" do %>
<%= image_tag post.user.image, class: "user-icon4" %>
<%end%>
<% else %>
<%=link_to user_path(post.user.id) ,class:"user-icon4" do %>
<%= image_tag "willy.png", alt: "user-icon", class: "user-icon4" %>
<%end%>
<% end %>
</div>
<div class="item-create">
<div class="item-user-name">
<%= link_to post.user.nickname, user_path(post.user.id) %>
</div>
<div class="created_at" >
<%=post.created_at.strftime('%Y/%m/%d')%>
</div>
</div>
<div class="good-county">
<i class="fas fa-thumbs-up"></i> <%=post.likes.count%>
</div>
</div>
<% end %>
</li>
<% end %>
</ul>
</div>
<%= link_to new_item_path, class: 'item-btn' do %>
<span class='item-btn-text'>Post Review</span>
<%= image_tag 'icon_camera.png' , size: '79x50' ,class: "item-btn-icon" %>
<% end %>
</div>
<%= render "shared/footer" %>
5.まとめ
以上でフォロー機能の実装は完成でーす!
以下のように表示されたらOK!です!
ありがとうございました。
この記事が気に入ったらサポートをしてみませんか?