【Ruby on Rails】フォロー機能実装：双方向

# 目標
![follow.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700999/8d494479-610a-7244-5079-1fd7a0a2aac8.gif)

# 開発環境
ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina

# 前提
※　▶◯◯　を選択すると、説明等が出てきますので、
　　よくわからない場合の参考にしていただければと思います。

- [deviseでログイン環境構築](https://qiita.com/japwork/items/275110b810965fbdf72f)

※[一方向のブックマーク（お気に入り登録、いいね）機能はこちら](https://qiita.com/japwork/items/3ca48e7c5fa1053b910b)

# 流れ

1 modelを作成
2 modelを修正　<-- ここが一番むずかしいです
3 controllerを作成
4 routingを修正
5 viewを作成

# modelの作成
今回はRelationshipモデルを作成

```:ターミナル
$ rails g model Relationship follower_id:integer followed_id:integer
```
```:ターミナル
$ rails db:migrate
```
<details><summary>補足</summary>
follower_idとfollowed_idは架空のidであり、後ほどuserモデルの修正にて記述し、使用します。</details>

# modelを修正
```rb:app/models/relationship.rb
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "User"
```
<details><summary>補足</summary>
メソッド名を変更し、@relationship.followerのような形で、@relationshipに紐づいたuserレコードを取得。
※メソッド名変更は、フォローとフォロワーを分けるためです。</details>

```rb:app/models/user.rb
  has_many :follower, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy # フォロー取得
  has_many :followed, class_name: "Relationship", foreign_key: "followed_id", dependent: :destroy # フォロワー取得
  has_many :following_user, through: :follower, source: :followed # 自分がフォローしている人
  has_many :follower_user, through: :followed, source: :follower # 自分をフォローしている人

  # ユーザーをフォローする、後ほどcontrollerで使用します。
  def follow(user_id)
    follower.create(followed_id: user_id)
  end
  
  # ユーザーのフォローを外す、後ほどcontrollerで使用します。
  def unfollow(user_id)
    follower.find_by(followed_id: user_id).destroy
  end
  
  # フォローしていればtrueを返す、後ほどviewで使用します。
  def following?(user)
    following_user.include?(user)
  end
```
<details><summary>補足１【１，２行目について】</summary>
＜has_many :follower＞
　まず、userは多くのfollowerを持ち、
＜class_name: "Relationship"＞
　@userに紐づいた@relationshipレコードを取得可能にし、
＜foreign_key: "follower_id"＞
　relaitonshipsテーブルにアクセスする時、follow_idを入口とし、
＜dependent: :destroy＞
　userがなくなれば削除する</details>

<details><summary>補足２【３，４行目について】</summary>
＜has_many :following_user＞
　まず、userは多くのfollowing_userを持ち、
＜through: :follower＞
　followerを通してfollowing_userを取得可能にし、
＜source: :followed＞
　user.following_userで取得可能にする。</details>

<details><summary>補足３【(followed_id: user_id)について】</summary>
(followed_id: user_id)は
followed_id　に　user_idを代入する
という風にイメージするとわかりやすいです。
あとは文字通りの意味です。</details>

# controllerを作成
```:ターミナル
$ rails g controller relationships
```
```rb:app/controllers/relationships.controller.rb
  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
```
今回はapp/views/homes/mypage.html.erbに
フォロー、フォロワーの一覧を表示するため下記の場所に記述。

```rb:app/controllers/homes.controller.rb
  def mypage
    @following_users = current_user.following_user
    @follower_users = current_user.follower_user
  end
```

# routingを修正
```rb:config.routes.rb
resources :users do
  resource :relationships, only: [:create, :destroy]
end
```

# viewに追加(インスタンス変数ありの場合）
```erb:app/views/show.html.erb
<% if current_user != user %>
  <% 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 %>
<% end %>
```

```erb:app/views/homes/mypage.html.erb
<div>
  フォロー数： <%= current_user.follower.count %>
  フォロワー数：<%= current_user.followed.count %>
</div><br><br>
<table>
	<caption>フォロー中</caption>
	<thead>
		<tr>
			<th>ユーザー名</th>
			<th></th>
		</tr>
	</thead>
	<tbody>
		<% @following_users.each do |following_user| %>
		<tr>
			<td><%= following_user.name %></td>
			<td><%= link_to 'フォロー外す', user_relationships_path(following_user.id), method: :delete %></td>
		</tr>
		<% end %>
	</tbody>
</table><br><br>

<table>
	<caption>フォロワー</caption>
	<thead>
		<tr>
			<th>フォロワー名</th>
		</tr>
	</thead>
	<tbody>
		<% @follower_users.each do |follower_user| %>
		<tr>
			<td><%= follower_user.name %></td>
		</tr>
		<% end %>
	</tbody>
</table>
```

# 参考

- [Railsでフォロー機能を作る方法](https://qiita.com/mitsumitsu1128/items/e41e2ff37f143db81897)
- [アソシエーションにおけるclass_nameの定義！](https://qiita.com/wacker8818/items/eccdf0a63616feb14a70)
- [【Rails】多対多のアソシエーションに別名をつけたいあなたに](https://kimuraysp.hatenablog.com/entry/2017/09/05/235816)