フォロー機能（Ajax）実装

自分用にまとめます。

# 実装

モデル作成

```
$ rails g model Relationship follower_id:integer followed_id:integer
$ rails db:migrate
```

<br>

マイグレーションファイル

```20200723070930_create_relationships.rb
class CreateRelationships < ActiveRecord::Migration[5.2]
  def change
    create_table :relationships do |t|
      t.integer :follower_id, null: false
      t.integer :followed_id, null: false

      t.timestamps
    end
  end
end
```

<br>

```ruby:relationship.rb
class Relationship < ApplicationRecord

  # フォローするユーザー
  belongs_to :follower, class_name: 'User'
  # フォローされるユーザー
  belongs_to :followed, class_name: 'User'

  validates :follower_id, presence: true
  validates :following_id, presence: true

end
```
**class_name: 'User'**:「followerもfollowedもUserにいるよ」という意味

<br>

```ruby:app/models/user.rb
class User < ApplicationRecord

  # フォロー取得
  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


  # ユーザーをフォローする
  def follow(user_id)
    follower.create(followed_id: user_id)
  end

  # ユーザーのフォローを外す
  def unfollow(user_id)
    follower.find_by(followed_id: user_id).destroy
  end

  # フォロー確認を行う
  def following?(user)
    following_user.include?(user)
  end

end
```

<br>


コントローラ作成

```
$ rails g controller relationships
```

<br>

```ruby:config/routes.rb
Rails.application.routes.draw do

  post 'follow/:id', to: 'relationships#follow', as: 'follow'
  post 'unfollow/:id', to: 'relationships#unfollow', as: 'unfollow'
  get 'users/following/:user_id', to: 'users#following', as: 'users_following'
  get 'users/follower/:user_id', to: 'users#follower', as: 'users_follower'

end
```

<br>

```ruby:users_controller.rb
class UsersController < ApplicationController

  # @userがフォローしているユーザー一覧
  def following
    @user = User.find(params[:user_id])
    @followings = @user.following_user
  end

  # @userをフォローしているユーザー一覧
  def follower
    @user = User.find(params[:user_id])
    @followers = @user.follower_user
  end

end
```
<br>


```ruby:relationship_controller.rb
class RelationshipsController < ApplicationController

    # フォローする
    def follow
      @user = User.find(params[:id])
      current_user.follow(params[:id])
      render :create
    end
  
    # アンフォローする
    def unfollow
      @user = User.find(params[:id])
      current_user.unfollow(params[:id])
      render :destroy
    end
    
end
```

renderでcreate.js.erbとdestroy.js.erb呼び出すことで、
ページ遷移なしでフォロー・解除が行えるようになる。

<br>


```ruby:users/show.html.slim
# create.js.erbとdestroy.js.erbで書き換えるため記述必須
div id="follow_form"

  # フォローボタン部分をパーシャルで飛ばす
  = render 'relationships/follow', user: @user 
```

<br>


_follow.html.slimファイルをrelationshipsディレクトリ配下に手動で作成
パーシャルで飛ばしたフォローボタン部分の記述を貼り付ける。

```ruby:relationships/_follow.html.slim
- unless user == current_user
  - if current_user.following?(user)
  
    # jsファイルを呼び出すためにremote: trueを追記
    = link_to unfollow_path(user), method: :post, remote: true, class: 'btn btn-outline-info m-0 btn-sm' do
      i.fas.fa-user フォロー中
  - else
  
    # jsファイルを呼び出すためにremote: trueを追記
    = link_to follow_path(user), method: :post, remote: true, class: 'btn btn-outline-success m-0 btn-sm' do
      i.far.fa-user フォローする
```

<br>


create.js.erbファイルをrelationshipsディレクトリ配下に手動で作成

```ruby:relationships/create.js.erb

#　id="follow_form"部分を_follow.html.slimの内容にページ遷移なしで書き換える
$('#follow_form').html("<%= j(render 'relationships/follow',{ user: @user }) %>");
```
<br>


destroy.js.erbファイルをrelationshipsディレクトリ配下に手動で作成

```ruby:relationships/destroy.js.erb

#　id="follow_form"部分を_follow.html.slimの内容にページ遷移なしで書き換える
$('#follow_form').html("<%= j(render 'relationships/follow',{ user: @user }) %>");
```



**完成!**