フォロー機能のアソシエーション備忘録(Userモデルの記述を理解する)

##　目次
- [はじめに](#はじめに)

- [多対多なので中間テーブルを作成](#多対多なので中間テーブルを作成)

- [モデルを2つに分けて考える(ここ重要)](#モデルを2つに分けて考えるここ重要)

- [①フォローする側の目線で考える](#フォローする側の目線で考える)

- [②フォローされる側の目線で考える](#フォローされる側の目線で考える)

- [まとめ](#まとめ)


##　はじめに
ここ数日間、フォロー機能のアソシエーションを理解するのにもがき苦しんだわけですが、やっと自分の中に落とし込むことができたので備忘録として残します。

個人的に**Userモデルへのアソシエーションの記述**のところで頭がごちゃごちゃになって詰まったので、そこを中心に書いています。ですので今回は、viewやcontrollerの実装に関しては触れていません。

ということで早速始めます。

##　多対多なので中間テーブルを作成

フォロー機能のアソシエーションは、多対多(user対user)のアソシエーションなので、
中間テーブルを用意して「一対多」(user対relationships)のアソシエーションにしていく必要がある。

(一対多とか多対多とかなんのこっちゃっという方には[【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】](https://qiita.com/kazukimatsumoto/items/14bdff681ec5ddac26d1#%E3%83%95%E3%82%A9%E3%83%AD%E3%83%BC%E3%83%95%E3%82%A9%E3%83%AD%E3%83%AF%E3%83%BC%E6%A9%9F%E8%83%BD%E3%82%92er%E5%9B%B3%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E8%A8%AD%E8%A8%88%E3%81%97%E3%82%88%E3%81%86)の記事がオススメです。私もこれを何回も見て、学習しました。)

ということでまずはrelationshipモデルを作成する。

```ターミナル
$ rails g model Relationship
```

マイグレーションファイルに、following_id(フォローする側のid)とfollower_id(フォローされる側のid)などを追加する。

```ruby:202008111333110_create_relationships.rb
class CreateRelationships < ActiveRecord::Migration[5.2]
  def change
    create_table :relationships do |t|
      #フォローする側
      t.integer :following_id
      #フォローされる側   
      t.integer :follower_id

      t.timestamps null: false
    end
    add_index :relationships, :following_id
    add_index :relationships, :follower_id    
    add_index :relationships, [:following_id, :follower_id], unique: true
  end
end
```
忘れずに・・・

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


## モデルを2つに分けて考える(ここ重要)

ここからは
　**①フォローする側の目線**
　**②フォローされる側の目線**
この2つをしっかり区別して考える必要がある。
曖昧にすると何が何だか分からなくなるので注意！

まずは・・・
**1. Relationshipモデルを2つに分けて考える**
  ・active_relationships (フォローする側の目線)
  ・passive_relationships (フォローされる側の目線)

```user.rb
class User < ApplicationRecord
  has_many :active_relationships, class_name: "Relationship", foreign_key: :following_id, dependent: :destroy
  has_many :passive_relationships, class_name: "Relationship", foreign_key: :follower_id, dependent: :destroy
end
```

あくまでも、1つのRelationshipモデルをそれぞれ名前を付けて2つのモデルに分けたという“想定”に過ぎないため、本当はRelationshipモデルであることをclass_nameで記載する必要がある。

また、フォローをする側の目線では、フォローする側(following_id)を元にフォローされる側(follower_id)を引っ張ってくるので、primary_key(外部キー)をfollowing_idに指定する必要がある。

逆に、フォローされる側の目線では、フォローされる側(follower_id)を元にフォローする側(following_id)を引っ張ってくるので、primary_key(外部キー)をfollower_idに指定する必要がある。

**2. Userモデルを2つに分けて考える**
     ・ following (フォローする側の目線)
     ・ follower (フォローされる側の目線)

```relationship.rb
class Relationship < ApplicationRecord
  belongs_to :following, class_name: "User"
  belongs_to :follower, class_name: "User"
end
```

Relationshipモデルと同様にあくまでも、1つのUserモデルをそれぞれ名前を付けて2つのモデルに分けたという“想定”に過ぎないため、本当はUserモデルであることをclass_nameで記載する必要がある。


##①フォローする側の目線で考える


1行目：**Relationshipsモデル(ここではフォローする側目線なのでactive_relationships)について記述**
上記ののRelationshipsモデルを2つに分けるところで説明済み。

2行目：**active_relationshipを介してフォローされた人を集める**
active_relationshipsを通ってフォローされた人を集める。フォローされた人を集めるには、"follower"モデルを参照することになるため、source: :followerを記述する。この一連の流れを"followings"と命名したのでhas_many :followingsと記述する。

```user.rb
  has_many :active_relationships, class_name: "Relationship", foreign_key: :following_id
  has_many :followings, through: :active_relationships, source: :follower
```

##②フォローされる側の目線で考える

1行目：**まずはRelationshipsモデル(ここではpassive_relationships)について記述**
上記ののRelationshipsモデルを2つに分けるところで説明済み。

2行目：**passive_relationshipを介してフォローした人を集める**
passive_relationshipsを通ってフォローされた人を集める。フォローされた人を集めるには、"following"モデルを参照することになるため、source: :followingを記述する。この一連の流れを"followers"と命名したのでhas_many :followersと記述する。

```user.rb
  has_many :passive_relationships, class_name: "Relationship", foreign_key: :follower_id
  has_many :followers, through: :passive_relationships, source: :following
```

ということでUserモデルへの最終的な記述は以下のようになる。



```user.rb
class User < ApplicationRecord
  #フォローする側の目線
  has_many :active_relationships, class_name: "Relationship", foreign_key: :following_id
  has_many :followings, through: :active_relationships, source: :follower

  #フォローされる側の目線
  has_many :passive_relationships, class_name: "Relationship", foreign_key: :follower_id
  has_many :followers, through: :passive_relationships, source: :following
end
```

これにて終了。

## まとめ

フォロー機能を完成させるためには、別途viewやcontrollerの実装が必要です。

とは言ってもフォロー機能実装の山は、「Userモデルの記述を理解すること」にあると実際に自分が経験してみて感じたので、この山を越えればあとは難なく実装できると思います:thumbsup:

今回のポイントは、**1つのモデルを2つに分けて考える**というところだと思います。

そもそもフォローする人、フォローされる人の両方がUserモデルという1つのモデルを参照してデータを持ってくるという構造が話をややこしくしているので、いいね機能のPostモデルとUserモデルの関係みたいに、Userモデルを(本当は1つのモデルだけど)2つのモデルと想定して関係性を整理すれば、案外シンプルな話なのかもしれないと自分の中に落とし込むことができるのではないかと思います。

ここまで読んでいただきありがとうございました。
まだまだ知識が足りていない初心者なので、どこか突っ込みどころ・誤りなどがあれば是非是非アドバイスいただければ幸いです。