フォロー機能の追加方法(Ruby on Rails)

##今回の課題 "フォロー機能の追加"

Railsでのフォロー機能の追加について難しかった点などを
自分で記事に書いて、頭の中を整理していこうと思います。
間違いなどありましたら、ご教授の程よろしくお願い致します。

##開発環境
> ruby 2.6.3
> Rails 5.2.6
> Bootstrap 4.5
> Cloud9

##大事なこと
今回はフォローした人とフォローする人
どちらも同じテーブル内に存在するUserです。
多くの人をフォローすることもできるし、多くの人にフォローされることもある状態なので現在は多対多の関係になっています。なので
`1対Nの関係を中間テーブルを用いて関連付ける`事が重要になります。

自分自身もまだ完全には理解できていませんが、この記事を書く事で少しでも理解できる様に整理していきます。

##手順
- モデルの作成
- アソシエーション
- メソッド作成
- コントローラー
- ビュー

##モデルの作成
まずは`relationship`モデルを作成

そしてrelationshipsテーブル内のカラムに
・integer :follower_id(フォローしたUser)
・integer :followed_id(フォローされたUser)
の2つのカラムを追加します。

```
$ rails g model Relationship follower_id:integer followed_id:integer
$ rails db:migrate
```
##アソシエーション
関係性を整理すると
`"1人のUserは多くの人をフォローできる"`
`"1人のUserは多くの人からフォローされる"`
と考えると1対Nの関係性が出来上がります。

###Relationshipモデル

```models/relationship.rb
class Relationship < ApplicationRecord
  # belongs_to :userにするとフォローするuserなの?フォローされるuserなの?となる
  # このままだと存在しないテーブルを探しに行くので、class_name: で"User"を指定
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "User"
end
```

###Userモデル

```models/user.rb
#foreign_keyには、@user.xxxとした際に「@user.idがfollower_idなのかfollowed_idなのか」を指定する
#フォローした人、された人の関係性を記述
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
```

続いてモデルにメソッドを記述していきます。

```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)
  following.include?(user)
end
```

こう記述することでコントーローラ内の記述を見やすくする。

##Relationshipsコントローラーの作成と記述

```
$ rails g controller Relationships
```


```controllers/relationships_contoller.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
  end
end
```
コントローラ作成後、ルーティングも設定します。

```config/routes.rb
#ネストさせる

 resources :users do
  resource :relationships, only:[:create, :destroy]
  get "followings" => "relationships#followings", as: "followings" 
  get "followers" => "relationships#followers", as: "followers"
 end

```

##ビューの記述をする

フォローボタンの設置

```erb:お好きなところ
 #もしログインユーザーがフォローしてる一覧内に、(user)が含まれていたら?
 <% if current_user.followings?(user)%>
  <%= link_to "フォロー外す", user_relationships_path(user.id), method: :delete %>
 <% else %>
  <%= link_to "フォローする", user_relationships_path(user.id), method: :post %>
 <% end %>
```

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

```erb:部分テンプレート
#もしユーザーが存在したら一覧表示(usersには@変数を入れる)
<% 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 %>

```

あとは部分テンプレートを、render で呼び出して各ビューに貼る

##まとめ

最後の方は文章などが少なくなりましたが、記述の内容をちゃんと理解して
流れを理解できる様になればもっとわかる様になると思いました。

もっと日々勉強を続けて、スキルアップしていける様に努力します。