Ruby on Rails チュートリアル 14章　フォロー機能


## はじめに
Ruby on Railsチュートリアルの備忘録
チュートリアル学習者向けに書いています。
あとは備忘録
14章の内容です。この章は、モデル設計を理解するのが1番の重要で、これさえ理解できれば消化試合です。
チュートリアルと合わせてご覧ください。

## migration生成
```rb
# referencesは使わない
# user_id:referenceだとuser_id modelを探しに行く挙動
rails generate model Relationship follower_id:integer followed_id:integer
```

```rb
class CreateRelationships < ActiveRecord::Migration[6.0]
  def change
    create_table :relationships do |t|
      t.integer :follower_id
      t.integer :followed_id

      t.timestamps
    end
    # 総フォロー数やフォロワー数はよく問い合わせるのでindex
    add_index :relationships, :follower_id
    add_index :relationships, :followed_id
    # 下記は一意生のために必要。 
    # フォローボタンを連打してもAがBをフォローは必ず1つになる
    add_index :relationships, [:follower_id, :followed_id], unique: true
  end
end
```

## `has_many`
*`has_many`はメソットを作るためのメソットである*
`Userモデル`
```rb
class User < ApplicationRecord

# UserのidとMicropostのuser_idを紐づける
has_many :microposts, dependent: :destroy
# Default: class_name : "Micropost"
# Default: foreign_key: "user_id"

# UserのidとRelationshipのfollower_idを紐づける
# active_relationshipsメソッドを作成(自身[が]フォローしてるrelationshipデータを全て取得)
has_many :active_relationships, class_name:  "Relationship",
                                  foreign_key: "follower_id",
                                  dependent:   :destroy
# Defaultではない設定
# class_name : Relationship
# foreign_key: follower_id

# @user.active_relationships.buildと
# すると自動的にfollower_idにuserを設定
```

## `belongs_to`
`Relationshipモデル`
```rb
class Relationship < ApplicationRecord

# Relationshipのfollower_idとUserのidを紐づける
# followerメソッドを生成(そのデータのフォローしているuserを特定)
  belongs_to :follower, class_name: "User"
  # foren_key: follower_id
  # class: User
  # Relationship.first.followerが使える
  
  # DefaultだとclassはFollowerになってしまう
  
  belongs_to :followed, class_name: "User"
  # Relationship.first.followedが使える
end
```

## バリデーションを追加
*テストを書くなら`generate`で自動生成された`fixture`を削除*

`app/models/relationship.rb`

```rb
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
validates :follower_id, presence: true
validates :followed_id, presence: true
```

---

## `has_many through`
*上記の`has_manyやbelong_to`を実装したことで下記実装を行える*

## user.followingを作成(フォロー)

`app/models/user.rb`
```rb
class User < ApplicationRecord
.
.
# following メソッドを生成する(フォローしている人を全て特定する) @user.following

# Userインスタンスにactive_relationshipsメソッドを実行 (自身[が]フォローしているrelationshipデータを全て取得)
# 得られたdata1つ1つにfollowedメソッドを実行(誰をフォローしているのか特定)
has_many :following, through: :active_relationships, source: :followed
.
.
end

------------------------------------------------------------

#　関連づけをしたことによりフォローしているユーザーを配列のように扱うことができる
user.following.include?(other_user)
user.following.find(other_user)

# followingで取得したオブジェクトは、配列のように要素を追加したり削除したりすることができる。
user.following << other_user # 配列の最後に追記
user.following.delete(other_user)
```



## user.followersを作成(フォロワー)
`app/models/user.rb`

```rb
class User < ApplicationRecord
.
.
# UserのidとRelationshipのfollowed_idを紐づける
# passive_relationshipsメソッドを作成(自分[を]フォロー全てのrelationshipデータを取得)
  has_many :passive_relationships, class_name:  "Relationship",
                                   foreign_key: "followed_id",
                                   dependent:   :destroy
                                   
  has_many :followers, through: :passive_relationships, source: :follower
.
.
end
```

## 便利メソッドを作成する
`app/models/user.rb`
```rb
# ユーザーをフォローする
  def follow(other_user)
    following << other_user
  end

  # ユーザーをフォロー解除する
  def unfollow(other_user)
    active_relationships.find_by(followed_id: other_user.id).destroy
  end

  # 現在のユーザーがフォローしてたらtrueを返す
  def following?(other_user)
    following.include?(other_user)
  end
```



*これ以降はrails tutorial 14章を参照*