🍎

【Rails】フォロー機能実装

2023/08/02に公開

はじめに

  • アプリケーション作成済
  • 「relationshipsコントローラー」「ralationshipモデル」を使用して実装
  • 完成イメージ ↓
    altテキスト
    altテキスト

1.Relationshipモデル、relationshipsテーブルを作成

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

実行結果として下記が表示されればOK!

ターミナル
Running via Spring preloader in process 11300
      invoke  active_record
      create    db/migrate/20230801101147_create_relationships.rb
      create    app/models/relationship.rb
      invoke    test_unit
      create      test/models/relationship_test.rb
      create      test/fixtures/relationships.yml
ターミナル
$ rails db:migrate
  • ここまでで「Relationshipモデル」「relationshipsテーブル」が生成された
  • 「follower_id:integer」「followed_id:integer」=カラムを外部キーとして生成
  • 「user_id」ではないのはなぜか?
     - フォロー機能の場合、userがuserをフォローするため、「Userテーブル同士を結ぶ必要がある」
     - このことからフォローする側もフォローされる側も「user_id」となってしまうので、中間テーブルである「relationshipsテーブル」を作成し、「follower_id」「followed_id」を用意した。

2.アソシエーションを設定

app/models/relationship.rb
class Relationship < ApplicationRecord
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "User"
end
  • 「belongs_to :follower」だと、存在しないfollowersテーブルを探しに行くためエラーが出てしまう
  • 「belongs_to :follower, class_name: "User"」とすることで、「usersテーブル」を探しに行くようになる
app/models/user.rb
class User < ApplicationRecord
:
:
#フォローする、フォローされた 関係
#has_many :アソシエーションが繋がっているテーブル名, class_name: "モデルの名前", foreign_key: 外部キーとして持っているカラム
  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 :テーブル名, through: :中間テーブル名
#@user.following_users でそのuserがフォローしている人の一覧表示
  has_many :following_users, through: :followers, source: :followed
#@user.follower_users でそのuserがフォローされている人の一覧表示
  has_many :follower_users, through: :followeds, source: :follower
:

3.Userモデルにメソッドを定義

app/models/user.rb
class User < ApplicationRecord
:
:
 #フォローするときの処理
  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
end

4.ルーティング設定

  • アソシエーション設定で「user」と「Relationship」を繋げたため、user_idを取得できるようにネストする
  • createアクション(フォローする)、destroyアクション(フォローをはずす)を記述
config/routes.rb
Rails.application.routes.draw do
:
  resources :users, only: [:index, :show, :edit, :update ] do
    member do
      get :follows, :followers
    end
      resource :relationships, only: [:create, :destroy]
  end
:
ターミナル
$ rails routes

でルーティングを確認!

ターミナル
user_relationships DELETE  /users/:user_id/relationships(.:format)  relationships#destroy
                   POST    /users/:user_id/relationships(.:format)  relationships#create
  • ルーティングに「:user_id」が含まれている!

5.コントローラー作成

relationshipsコントローラーを作成

ターミナル
$ rails g controller relationships

ルーティングで設定したcreate、destroyアクションを記述

app/controllers/relationships_controller.rb
class RelationshipsController < ApplicationController
  
  def create
  end
  
  def destroy
  end
  
end

6.アクションを実装

app/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
  
end
app/controllers/users_controller.rb
class UsersController < ApplicationController
:
:
  #users/showページでフォロー数、フォロワー数を表示
  def show
    @user = User.find(params[:id])
    @book = Book.new
    @books = @user.books
    @following_users = @user.following_users
    @follower_users = @user.follower_users
  end

  #フォロー一覧
  def follows
    user = User.find(params[:id])
    @users = user.following_users
  end

  #フォロワー一覧
  def followers
    user = User.find(params[:id])
    @user = user.follower_users
  end
:

7.ビュー作成

users/showページに実装

app/views/users/show.html.erb
<tr>
  <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 %>  #ログインしている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>
</tr>

フォロー数、フォロワー数が表示された!
altテキスト

users/indexページにも実装

app/views/users/index.html.erb
<% @users.each do |user| %>
  <tr>
    <td><%= image_tag user.get_profile_image(100, 100) %></td>
    <td><%= user.name %></td>
    <td><%= link_to "show", user_path(user.id) %></td>
    <td>フォロー<%= user.followers.count %></td>  #フォロー数表示
    <td>フォロワー<%= user.followeds.count %></td> #フォロワー数表示
    <td>
      <% 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 %>
    </td>
  </tr>
<% end %>

フォロー数、フォロワー数が表示された!
altテキスト
altテキスト

8.フォロー、フォロワー 一覧ページを作成

app/views/usersに「followers.html.erb」「follows.html.erb」ファイルを作成
altテキスト

app/views/users/followers.html.erb
<h2>Follows</h2>
  <table class="table">
    <thead>
      <tr>
        <th>Image</th>
        <th>name</th>
        <th colspan="2"></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 %>
            <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>

app/views/users/follows.html.erb
<h2>Follows</h2>
  <table class="table">
    <thead>
      <tr>
        <th>Image</th>
        <th>name</th>
        <th colspan="2"></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>

フォロー一覧ページ
altテキスト

フォロワー一覧ページ(まだフォローされてないのでuserの表示なしの状態)
altテキスト


以上でフォロー機能の実装が完了となります!!

間違っている箇所などありましたら教えていただけると幸いです🙏

Discussion