【Rails6】非同期(Ajax)でフォロー機能を実装する

# 前提
- deviseでユーザーに関する機能作成済み
- jqueryが使える環境を構築済み

# 概要
フォロー機能の仕組みについては、RailsTutorialに詳しく書かれているので、参照することをお勧めします。今回用いるカラム名やモデル名は以下の通りです。メモ程度ですが参考程度に載せておきます。

![Untitled (13)-7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688968/e84a3cc0-3e0f-71db-a42b-a506f3961828.jpeg)

# Relationshipモデルを作成

コンソールでrelationshipモデルを作成

```console
rails g model relationships
```

- 参照
 - フォロワー：　userテーブルを参照する
 - フォロー ：　`followという名前で`userテーブルを参照する
- index
 - user_idとfollow_idが一致することが無い様に、複合キーインデックスを追加
 - これにより、「自分が自分をフォローする」ということを防げる

```20210104064312_create_relationships.rb
class CreateRelationships < ActiveRecord::Migration[6.0]
  def change
    create_table :relationships do |t|
      t.references :user, foreign_key: true
      t.references :follow, foreign_key: { to_table: :users }

      t.timestamps

      t.index [:user_id, :follow_id], unique: true
    end
  end
end
```
マイグレーションを実行

```
rails db:migrate
```

relationshipモデルとuserモデルのリレーションは以下の通り記述する。
また、validationも記述。

```rb:relationship.rb

class Relationship < ApplicationRecord
  belongs_to :user
  belongs_to :follow, class_name: 'User'

  validates :user_id, presence: true
  validates :follow_id, presence: true
end
```

- 関連付けについては、上記画像を参照していただけると幸いです。
- 「フォローする」「フォローを外す」「フォローしているか確認」のメソッドは何度も使用するので、定義しておきます。

```rb:relationship.rb
class User < ApplicationRecord
  has_many :relationships, dependent: :destroy
  has_many :followings, through: :relationships, source: :follow
  has_many :reverse_of_relationships, class_name: 'Relationship', foreign_key: 'follow_id', dependent: :destroy
  has_many :followers, through: :reverse_of_relationships, source: :user

  def follow(other_user_id)
    relationships.find_or_create_by(follow_id: other_user_id) unless id == other_user_id.to_i
  end

  def unfollow(other_user_id)
    relationship = relationships.find_by(follow_id: other_user_id)
    relationship.destroy if relationship
  end

  def following?(other_user)
    followings.include?(other_user)
  end
end
```

# view controllerの作成


- 自ユーザページの場合は、「編集ボタン」、他ユーザページの場合は、「フォローボタン」を表示する様にします。

```erb:app/views/users/show.html.erb

<div>
  <% if @user.id == current_user.id %>
    <%= link_to 'Edit', edit_user_registration_path(current_user) %>
  <% else %>
    <%= render partial: 'follow' %>
    <%= render partial: 'follow_count'%>
  <% end %>
</div>
```

```erb:app/views/users/_follow.html.erb

<span id="follow">
  <%= follow_button(@user) %>
</span>
```

- follow_buttonを定義しています。
- Bootstrapを使用している方は、フォロー中かどうかに応じてkeyにprimaryかsecondaryが入るため、ボタンの色を変えることができます。(Bootstrap不使用の方は消してしまって問題ないです。)
- `remote: true` を入れることによって、Ajax通信をすることができます。

```erb:app/helpers/application_helper.html.erb
module ApplicationHelper
  def follow_button(user)
    label, key = current_user.following?(user) ? %w[フォロー中 secondary] : %w[フォローする primary]
    link_to(label, user_follow_path(@user), method: :post, remote: true, class: "btn btn-#{key} rounded-pill")
  end
end
```

- javascriptで書かれています。
- `html内のidがfollowの中身をrenderする`ことができます。


```erb:app/views/users/follow.js.erb
$('#follow').html('<%= j(render partial: "follow") %>');
```

- 忘れずにrouteも変えましょう。
- post通信を行うために指定が必要です。

```rb:routes.rb
Rails.application.routes.draw do
  resources :users, only: %w[index show] do
    post :follow
  end
end
```


# 最後に
`@user.followers.count`や`@user.followings.count`で、フォロワー数やフォロー数をカウントして表示することが可能です。こちらの記事を理解することができていれば、簡単にAjaxで実装できるので、やってみてください。