フォロー機能がほしいぃぃ ❏Rails❏

`RailsTutorial`を参考にフォロー機能をつけました。

簡単にまとめます。

※クラス名・id名は本家と変えたところがあります。
※ところどころ自己流にアレンジしています。ご容赦ください。

#Relationshipモデル

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

```ruby:db/migrate/20191128014554_create_relationships.rb
class CreateRelationships < ActiveRecord::Migration[5.2]
  def change
    create_table :relationships do |t|
      t.integer :follower_id
      t.integer :followed_id

      t.timestamps
    end
    add_index :relationships, :follower_id
    add_index :relationships, :followed_id
    add_index :relationships, [:follower_id, :followed_id], unique: true
  end
end
```

```:ターミナル
$ rails db:migrate
```

```ruby:app/models/relationship.rb
class Relationship < ApplicationRecord
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "User"
  validates :follower_id, presence: true
  validates :followed_id, presence: true
end
```

#Userモデル

```ruby:app/models/user.rb
class User < ApplicationRecord
  略
  has_many :active_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy
  has_many :passive_relationships, class_name: "Relationship", foreign_key: "followed_id", dependent: :destroy
  has_many :following, through: :active_relationships, source: :followed
  has_many :followers, through: :passive_relationships, source: :follower

  def follow(other_user)
    following << other_user
  end

  def unfollow(other_user)
    active_relationships.find_by(followed_id: other_user.id).destroy
  end

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

#ルーティング

```ruby:app/config/locals/routes.rb
Rails.application.routes.draw do
  略
  resources :users, only: [:show] do
    member do
      get :following, :followers
    end
  end
  resources :relationships, only: [:create, :destroy]
end
```

#ビュー

```app/views/users/_stats.html.haml
- @user ||= current_user
%div
  = link_to following_user_path(@user) do
    #following
      = @user.following.count
  = link_to followers_user_path(@user) do
    #followers
      = @user.followers.count
```

```app/views/users/_follow_form.html.haml
- unless current_user == @user
  #follow_form
    - if current_user.following?(@user)
      = render 'unfollow'
    - else
      = render 'follow'
```

```app/views/users/_follow.html.haml
= form_for(current_user.active_relationships.build, remote: true) do |f|
  = hidden_field_tag :followed_id, @user.id
  = f.submit "Follow", class: "btn btn-primary"
```

```app/views/users/_unfollow.html.haml
= form_for(current_user.active_relationships.find_by(followed_id: @user.id), html: { method: :delete }, remote: true) do |f| 
  = f.submit "Unfollow", class: "btn"
```

```xxx.html.haml
#好きなところへ
= render "stats"
= render "follow_form" if user_signed_in?
```

<br>
以下２つは完全自己流なのでスルーしてください。

```ruby:following.html.haml
.contents
  = render "tweets/side-bar"
  .contents__right
    .contents__right__tweets
      .contents__right__tweets__follows
        .contents__right__tweets__follows__user-nickname
          = @user.nickname
          さん
        .contents__right__tweets__follows__text
          フォロー中
      - @users.each do |user|
        .contents__right__tweets__follow-users
          %p.contents__right__tweets__follow-users__user
            = link_to "#{user.nickname}", user_path(user)
      .contents__right__tweets__paginate
        = paginate(@users)
```

```ruby:followers.html.haml
.contents
  = render "tweets/side-bar"
  .contents__right
    .contents__right__tweets
      .contents__right__tweets__follows
        .contents__right__tweets__follows__user-nickname
          = @user.nickname
          さん
        .contents__right__tweets__follows__text
          フォロワー
      - @users.each do |user|
        .contents__right__tweets__follow-users
          %p.contents__right__tweets__follow-users__user
            = link_to "#{user.nickname}", user_path(user)
      .contents__right__tweets__paginate
        = paginate(@users)
```

本家は`show_follow.html.erb`というビューファイルを作って、そこにレンダリングしています。
僕は`following` `followers`２つのビューファイルを作りました。冗長かもしれませんが明確に分けて管理したかったのでこうしました。

#コントローラー

```ruby:relationships_controller.rb
class RelationshipsController < ApplicationController
  before_action :authenticate_user!

  def create
    @user = User.find(params[:followed_id])
    current_user.follow(@user)
    respond_to do |format|
      format.html { redirect_to @user }
      format.js
    end
  end

  def destroy
    @user = Relationship.find(params[:id]).followed
    current_user.unfollow(@user)
    respond_to do |format|
      format.html { redirect_to @user }
      format.js
    end
  end
end
```

```ruby:users_controller.rb
class UsersController < ApplicationController
  before_action :authenticate_user!, only: [:following, :followers]

  略

  def following
    @user = User.find(params[:id])
    @users = @user.following.page(params[:page]).per(3)
  end

  def followers
    @user = User.find(params[:id])
    @users = @user.followers.page(params[:page]).per(3)
  end
end
```

<br>
本家大正義`RailsTutorial`
>https://railstutorial.jp/chapters/following_users?version=5.1#cha-following_users

<br>
ではまた！