1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Railsでフォロー機能を実装する

Last updated at Posted at 2020-12-29

なぜこの記事を書いたのか

Railsでのフォロー機能について説明している記事はたくさんあります。

しかし、「自分フォローしているユーザーの一覧ページ」と「自分フォロしているユーザーの一覧ページ」までの実装手順を説明している記事は少なく感じました。

この「フォロー一覧」と「フォロワー一覧」ですが、Relationshipテーブルのカラムをよく考えて命名しておかないと、ややこしくなることがあります。

following, follower, follow, followedなど様々な命名方法が記事によって混在していますが、一番混乱しにくい命名方法で解説されている記事が少なかったため、改めて記事を作成することにしました。

まず結論から言います。

この記事では、フォローする側はfollowing、**フォローされる側はfollower**としておくとよく覚えておいてください。

普通の感覚だと、『フォローする側がfollowerじゃないの?』と感じるかもしれません。長くなるので詳しい説明は省きますが、仮にその命名方法を取った場合、あるユーザーの「フォロワー一覧」を表示する際に参照するカラムが、followerカラムではなく、もう一方のカラムになってしまうため、色々と不都合が起きます。

現時点でこの意味が分からなくても全く問題ないので、ここではとにかくフォローする側はfollowing、**フォローされる側はfollower**だということを認識しておいてください。

前提

  • MVCを理解している
  • 基本的なアソシエーションを理解している
  • Userモデルが作成してある

流れ

  1. Relationshipモデルを作る
  2. アソシエーションを組む
  3. ルーティングを組む
  4. コントローラーでアクションを定義
  5. ビューを編集

Relationshipモデルを作る

フォロー機能では、フォローする側もフォローされる側もUserであるため、Userテーブルのレコード同士で「多対多」の関係を作る必要があります。

これを実現するために、フォローするユーザーとフォローされるユーザーの情報を保存しておく中間テーブルを作る必要があります。

例えば、ユーザーAがユーザーBをフォローした場合は、以下のようにして情報を記録します。

Userテーブル

id name
1 ユーザーA
2 ユーザーB

Relationshipテーブル

id following follower
1 2

以下をターミナルに打ち込んで、実際に中間テーブルであるRelationshipテーブルを作ってみましょう。

$ rails g model relationship following_id:integer follower_id:integer
$ rails db:migrate

これでRelationshipという中間テーブルができました!
このテーブルの存在意義は、以下の2つの情報を保存しておくことです。

  • フォローするユーザーが誰なのかを示すfollowingカラム
  • フォローされるユーザーが誰なのかを示すfollowerカラム

アソシエーション

今作成したRelationshipモデルにあるfollowingfollowerという情報は、どちらも親であるUserテーブルから情報を参照する必要があります。(フォローする側もされる側もどちらもUserであるため。)

FollowingモデルとFollowerモデルを擬似的に作成することで、その参照先をうまく分けることができます。

Relationshipモデルを以下のように変更してください。

app/models/relationship.rb
class Relationship < ApplicationRecord
    belongs_to :following, class_name: "User"
    belongs_to :follower, class_name: 'User'
end

class_nameにUserと記述することで、それぞれの参照先がUserモデルであることを示しています。

次にUserモデル側にアソシエーションを記述しましょう。

まずは以下のコードをまとめて追加してください。

app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  #以下を挿入

  has_many :following, class_name: "Relationship", foreign_key: "following_id", dependent: :destroy
  has_many :follower, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy

  has_many :following_user, through: :following, source: :follower
  has_many :follower_user, through: :follower, source: :following

  def follow(user_id)
    following.create(follower_id: user_id)
  end

  def unfollow(user_id)
    following.find_by(follower_id: user_id).destroy
  end

  def following?(user_id)
    following_user.include?(user_id)
  end
end

順番に説明していきます。
まずは以下の部分について。

  has_many :following, class_name: "Relationship", foreign_key: "following_id", dependent: :destroy
  has_many :follower, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy

1つ目のhas_manyでは、Relationshipモデルのfollowing_idにuser_idを格納する作業を行っています。その際、foreign_keyでfolowings_idと明示的に格納したいカラムを指定しています。

2つ目のhas_manyでは、Relationshipモデルのfollower_idにuser_idを格納する作業を行っています。その際、foreign_keyでfollower_idと明示的に格納したいカラムを指定しています。

次に、以下の部分について。

  has_many :following_user, through: :following, source: :follower
  has_many :follower_user, through: :follower, source: :following

ここでは、自分がフォローしているユーザーと自分をフォローしているユーザーを簡単に取得するためにthroughを使った関連付けを行っているだけです。

こうすることで、例えば@user.following_userなどと記述することで自分がフォローしたユーザーの情報が取得できるようになります。

最後にこの部分について

  def follow(user_id)
    following.create(follower_id: user_id)
  end

  def unfollow(user_id)
    following.find_by(follower_id: user_id).destroy
  end

  def following?(user_id)
    following_user.include?(user_id)
  end
end

ここではフォローするための関数,フォローを外すための関数,ユーザーを既にフォローしているかを調べる関数をそれぞれ作成しています。

これでフォロー機能で一番難しいアソシエーションの記述が終わりました!
ここまできたら、あとは基本的なMVCを理解していれば簡単です!

ルーティング

フォローしたり、フォローを外すためのアクションを定義する準備として、まずは以下のようにしてルーティングを行いましょう。

config/routes.rb
  post 'follow/:id' => 'relationships#follow', as: 'follow'
  delete 'unfollow/:id' => 'relationships#unfollow', as: 'unfollow'

続いて、「フォロー一覧」と「フォロワー一覧」のページを作るために、以下のルーティングも行っておきます。

config/routes.rb
  resources :users, only: [:show] do
    # 以下を挿入
    get :following, :follower, on: :member
  end

コントローラー

続いてrelationshipsコントローラーでのアクションの定義です。

まずはrelationshipsコントローラーを、ターミナルに以下のコードを打ち込んで作成しましょう。

$ rails g controller Relationships new

以下のようにして、ユーザーをフォローできるfollowアクションと、ユーザーへのフォローを外すことができるunfollowアクションを定義します。

app/controllers/relationships_controller.rb
class RelationshipsController < ApplicationController
    def follow
      current_user.follow(params[:id])
      redirect_back(fallback_location: root_path)
    end
  
    def unfollow
      current_user.unfollow(params[:id])
      redirect_back(fallback_location: root_path)
    end
end

続いて、usersコントローラーで「フォロー一覧」と「フォロワー一覧」を表示するために必要なアクションも以下のようにして記述しておきます。

app/controllers/users_controller.rb
class UsersController < ApplicationController
    def show
        @user = User.find(params[:id])
    end

    # 以下を挿入

    def following
        @user  = User.find(params[:id])
    end
  
    def follower
        @user  = User.find(params[:id])
    end
end

あとはビューに記述していくだけです!!

ビュー

user#showページにフォローボタンやフォローを外すボタンを記述する時の例を載せておきます。

あくまで一例なので、自分のプロダクトに合うよう、適宜書き換えてください。

app/views/users/show.html.erb
<% if user_signed_in? %>
  <% unless @user == current_user %>
    <% if current_user.following?(@user) %>
      <%= link_to unfollow_path(@user.id), method: :delete, :style=>"color:#E0245E;" do %>
        <i class="fas fa-heart"></i>
      <% end %>
    <% else %>
      <%= link_to follow_path(@user.id), method: :post do %>
        <i class="far fa-heart"></i>
      <% end %>
    <% end %>
  <% end %>
<% end %>

以下は、「フォロー一覧」と「フォロワー一覧」に飛ぶためのリンクコードの例です。

app/views/users/show.html.erb
<a href="<%= following_user_path(@user) %>">
  <%= @user.following.count %> following
</a>
<a href="<%= follower_user_path(@user) %>">
  <%= @user.follower.count %> followers
</a>

また、「フォロー一覧」と「フォロワー一覧」では以下を参考にして、適宜自分の表示させたい情報を記述していきましょう。

app/views/users/following.html.erb
<% @user.following_user.each do |user| %>
  <% user.name %>
<% end %>
app/views/users/follower.html.erb
<% @user.follower_user.each do |user| %>
  <% user.name %>
<% end %>

これで完成です!お疲れ様でした!

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?