【Rails】フォロー・フォロワー機能

# 開発環境
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`は使用しません。

それでは、ターミナルでコマンドを実行していきます。

```ruby:ターミナル
$ rails g model Relationship follower_id:integer followed_id:integer
$ rails db:migrate
```    

これで、Relationshipモデルが完成です。
<br>

## アソシエーション

中間テーブルは、このアソシエーションのが１番の難所です。
まず、関係性を整理します。

`1人のユーザーはたくさんのユーザーをフォローできる(1:N)`
`1人のユーザーはたくさんのユーザーにフォローされる(1:N)`

#### relationshipモデル

1人のユーザーはたくさんのユーザーをフォローでき、フォローもされるます。
つまり、`belongs_to`で定義します。

searchesコントローラーのsearchアクションを定義します
```ruby:models/relationship.rb
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側のアソシエーションを定義しましょう。

```ruby:models/user.rb
# フォローをした、されたの関係
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
``` 
<br>
フォローをした、されたの関係から見ていきましょう。<br>
<br>

ここでは、`relationships`と`reverse_of_relationships`がありますが、
さきほどと同じ考え方で、わかりにくいため名前をつけています。
`class_name: "Relationship"`でRelationshipテーブルを参照します。

`foreign_key(外部キー)`で参照するカラムを指定しています。

次に、フォロー・フォロワーの一覧画面で、`user.followers`という記述で
フォロワーを表示したいので、`through`でスルーするテーブル、
`source`で参照するカラムを指定します。

上の例では、`reverse_of_relationships`テーブルから
`follower_id`のデータを参照します。

## メソッドの作成

モデルにメソッドを定義します。
<br>

```ruby:models/user.rb
# フォローしたときの処理
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
``` 
<br>

## コントローラー作成

relationshipsコントローラを作成します。
<br>
```ruby:ターミナル
$　rails g controller relationships followings followers
``` 
<br>

relationdhipsコントローラーに、createとdestroyアクションを追加します。
追加したら先ほどのメソッドを使って、コントローラーに記述します。
<br>

```ruby: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
  # フォロー 一覧
  def followings
    user = User.find(params[:user_id])
    @users = user.followings
  end
  # フォロワー 一覧
  def followers
    user = User.find(params[:user_id])
    @users = user.followers
``` 
<br>

## ルーティング

ルーティングも設定します。

```ruby:book.rb
# ネストさせる
  resources :users do
    resource :relationships, only: [:create, :destroy]
    get 'followings' => 'relationships#followings', as: 'followings'
    get 'followers' => 'relationships#followers', as: 'followers'
  end
``` 
<br>

## Viewの作成

#### フォローボタン

フォローボタンを設定したい箇所に配置してください。

```ruby:任意の場所
<% 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 %>
``` 

#### フォロー・フォロワー一覧画面

フォロー一覧もフォロワー一覧も同じ内容を表示するので、部分テンプレートを作成します。

```ruby:views/relationships/_follow_list.html.erb
<% 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 %>
``` 
<br>

このテンプレートをrenderで呼び出せばOKです！
<br>



これで完成です！お疲れ様でした！
あくまで備忘録なので足りない説明等多々あるかと思います。
行き詰まった際の助けになれば幸いです。