フォロー機能実装で詰まったところ


## find_or_create_byメソッド

```ruby
def follow(other_user)
  unless self == other_user #フォローしようとしてるother_userが自分ではないか検証
    self.relationships.find_or_create_by(follow_id: other_user.id)
  end
end
```
引数の条件に該当するデータがあればそれを返す`find_by(other_user)`、なければ新規作成`create(other_user)`
新規作成後、保存する

参考記事：[find_or_initialize_byとfind_or_create_byの違いとは？](https://qiita.com/taimuzu/items/0a21738d018f475d63ae)

## includesメソッド
```ruby
def following?(other_user)
  self.followings.include?(other_user)
end
```
##### include?メソッドとは？
引数で指定した要素が配列中に含まれてるか判定するメソッド

※selfはuser自身なのでuser。
self(自分自身)がfollowing(フォローしてる人たち)の中でother_userが含まれてるかどうか判定するってこと。
other_userが含まれていればtrueを返し、含まれてなければfalseを返す。

## relationshipモデルのマイグレーションファイル
```ruby
class CreateRelationships < ActiveRecord::Migration[5.2]
  def change
    create_table :relationships do |t|
      t.integer :follower_id
      t.integer :following_id

      t.timestamps null: false

      add_index :relationships, :follower_id
      add_index :relationships, :following_id
      add_index :relationships, [:follower_id, :follwing_id], unique: true #follow_idとfollowing_idの同じ組み合わせができないようにする設定
    end
  end
end
```

`add_index`がindexをつけることくらいはわかるが、そもそもindexって何のためにつけるんだっけ？
`add_index`の記述の箇所の意味がわからないということでこちらの記事が参考になった。

参考記事：[データベースにindexを貼る方法](https://qiita.com/seiya1121/items/fb074d727c6f40a55f22)

###### Q.indexは何のためにつける？
カラムからデータを取得するときに検索しやすいようにするため。例えば今回だったらfollowerカラムからfollwerを検索しやすいようにするため。データが3人だけとかならいらないけど、1万人とかになってくると検索するのに時間がかかるのでつけた方がいいってことみたい。


```ruby:add_indexの書き方
add_index :テーブル名, カラム名
```
上の例でいうと、relationテーブルのfollow_idカラム、relationテーブルのfollowing_idカラムってことになる。

## userモデルの書き方
```ruby:user.rb
has_many :follwing_relationships, foreign_key: "follower_id", class_name: "Relationship", dependent: :destroy
```
`follwing_relationships`モデルは実際には存在しない。あくまで便宜上こういうふうに設定してるだけ。このモデルはフォローしてる人たちのモデル。
なので`follower_id`が外部キーで設定されてる。

`class_name: "Relationship"`これはさっきも言ったけど、`follwing_relationships`モデルは実際には存在しなくて、実際に存在するのは"Relationship"モデルだから、名前は`follwing_relationships`ってなってるけど、名前だけで本当は"Relationship"のことだよ〜と言ってる。

`dependent: :destroy`これは結構単純で、あるuserが無くなったら、そのuserがフォローしてる人たちとのrelationも消えるようにする設定。userモデルとrelationshipモデルは従属関係にあって、userが消えると、そのuserのrelationship(userとfollow_idsの関係)も消えるということ。


```ruby:user.rb
has_many :follwings, through: :following_relationships
```
`has_many :follwings(モデル名)`でモデル間のアソシエーションを定義してる。`through: :following_relationships`これは中間テーブルを示してる。何度か出てきてるけど、名前は`following_relationships`だけど実際は`relationships`が中間テーブル。

要は、userモデル(フォローされてる人たち)とuserモデル(フォローしてる人たち)という2つのuserモデルの中間にrelationモデルがあるってこと。

##### アソシエーションを利用するための2つの条件
1. モデルクラスにhas_manyやbelongs_toなどのメソッドで関係が定義されている
2. 所属する側のテーブルに所属するモデル名_idというカラムがある

特に2.は忘れがちなので注意!!
今回だと、following_idが必要ということだけど、上記のマイグレーションファイルのところ見てもらうと、あそこでfollowing_idを入れてあるのがわかると思うけど、今回はそこで定義してるからOK。

```ruby:user.rb
def following?(other_user) 
  following_relationships.find_by(following_id: other_user.id)
end

def follow!(other_user)
  following_relationships.create!(following_id: other_user.id)
end

def unfollow!(other_user)
  following_relationships.find_by(following_id: other_user.id).destroy
end
```
`find_by`メソッドは1件しか返さない。なので、これを設定しておけば、ピンポイントで探したいuserを探せる。
参考記事：[【Rails】世界で一番詳しいfind_byメソッドのいろいろな使い方](https://pikawaka.com/rails/find_by#find_by%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E5%A0%B4%E9%9D%A2%E3%81%A8%E3%81%AF%EF%BC%9F)

`create!`はそのまま保存するって意味。

最後のは1件userを見つけてきて、`.destroy`メソッドは消すだからそのデータを消すってこと。


僕がまだよく理解できてないのが、なぜモデルにメソッドを書くのか？
普通こういうメソッドはcontrollerに書くものと思ってたけど。
探したらこんな記事見つけた。
[Railsのモデルに書いたメソッドってどうやってコントローラで使うの？](https://qiita.com/leavescomic1/items/99f32f45cd04035f146c)

それでわかったのが、controllerの記述を出来るだけシンプルにするため。ってことみたい。
確かに上記の記述をcontrollerに書いたらごちゃごちゃしててわかりづらくなりそうだ。


## マイグレショーンファイルのエラー
`Caused by:Mysql2::Error: Table '（アプリ名）_development.relationships' doesn't exist`
「マイグレーション Table doesn't exist」で検索してみたら、この記事が出てきた。
参考記事：[Rails5.1に移行後のmigrationファイルの注意](https://qiita.com/umeneri/items/b46c537661f612f7318b)

### ルーティング 
```ruby:routes.rb
resources :users do
  member do
    get :following, :followers
  end
end
```
##### Q.`member`って何？どういう意味？
参考記事：[railsのroutes.rbのmemberとcollectionの違いをわかりやすく解説してみた。〜rails初心者から中級者へ〜](https://qiita.com/hirokihello/items/fa82863ab10a3052d2ff)

```ruby
following_user GET    /users/:id/following(.:format)                                                           users#following
followers_user GET    /users/:id/followers(.:format)                                                           users#followers
```
URLを見てもらうとわかるように、:idが自動で追加されるようになる。


## relationshipモデルのidが空になってるというエラー
![スクリーンショット 2020-06-20 06.55.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547640/c0baca69-79db-839a-3d86-d239d8dabb27.png)

```ruby:user.rb
has_many :following_relationships, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy

def following?(other_user)
  following_relationships.find_by(following_id: other_user.id)
end
```
following_relationshipsはRelationshipモデルを指してる。
following?メソッドはother_userという1人のユーザーを引数にとり、フォローする相手のユーザーがデータベース上に存在するかどうかをチェックする。

今回のエラーは、フォローする相手のuserのidが定義されていなくて空になってるよというエラー。

## 参考にさせて頂いた記事
[railsでフォロー機能をつける。](https://qiita.com/kitaokeita/items/59b625e0c43a62f5fe6a)
この記事を見ながらフォロー機能を実装しました。
[データベースにindexを貼る方法](https://qiita.com/seiya1121/items/fb074d727c6f40a55f22)
[find_or_initialize_byとfind_or_create_byの違いとは？](https://qiita.com/taimuzu/items/0a21738d018f475d63ae)
[Railsのモデルに書いたメソッドってどうやってコントローラで使うの？](https://qiita.com/leavescomic1/items/99f32f45cd04035f146c)