【Rails】アソシエーション/N+1問題

今回は今までの投稿データを取得する時の方法と、

ユーザー情報もくっつけて投稿データを取得するための方法の違いと、

後者のそのやり方についてみていきましょう。

 

今まではPost.allで投稿の情報を取得していましたね。

ただ今回ユーザー情報も一緒に取得するとなると、また別のテーブルから

情報を引っ張って来る必要が出てきます。

実際にはpostsテーブルから投稿データ、userテーブルからuser_idの取得が

必要になりますね。

 

これでは記述が多くなってしまうので予めテーブル同士で関連づけて、

テーブル間で情報のやりとちできるようにしておくことができます。

この概念のことをアソシエーションと呼びます。

アソシエーションとはモデルを利用したテーブル同士を関連づけのことです。

 

アソシエーションをモデルに定義することで、

そのモデルに紐づく別のモデルにアクセスができるようになります。

 

この時、1対多の関係になるのか1対1の関係になるのか、

この概念が非常に重要となってきます。

 

例えばUserモデルの視点に立つと、1人のユーザーは複数の投稿を所有します。

この1対多の状態をhas_manyの関係といいます。

この1対多の繋がりがあるということを示すのがhas_manyメソッドです。

 

Userモデル(user.rb)を編集しましょう。

has_many : posts

 

ではPostモデルの視点ではどうか。

一つの投稿は必ず一人のユーザーによるもの。つまり1対1の関係です。

この状態はbelongs_toの関係といいます。

同じようにこの繋がりを示しておきましょう。

 

Postモデル(post.rb)

belongs_to  : user

 

これで双方のモデルを通して情報のやりとりが

できるようになりました!

 

ここで、このアソシエーションを利用した場合にかぎり

起こってしまう問題を考えてみましょう。

 

それはデータベースへのアクセス回数が多くなってしまうことです。

Post. allでデータを取得すれば全てのデータを

一度のデータベースへのアクセスで取得できますね。

 

ただ今回のようにuser_idを紐づけてしまうと、

投稿数と同じ回数だけデータベースへのアクセスが必要になります。

 

これはアプリケーションのパフォーマンスが著しく下がってしまうことに

繋がってしまうのです。

この問題をN+1問題といいます。

 

ではこのN+1問題の解決方法をみていきましょう。

利用するのはincludesメソッドです。

引数に関連モデルを指定し、一度のアクセスでまとめてデータを取得します。

 

こちらを処理を実行するときに指示するので、

コントローラーに記載します。

 

(postsコントローラー)

def index

  @posts = Post . includes ( : user )

end

 

このincludesメソッドを使用すると全てのデータが取得されるので、

元々記載されていたallメソッドは不要になります。

 

そして最後に、このアソシエーションによってuser_idが紐づけられ、

投稿者の名前が表示されるようになれば、nameカラムも不要になりますね。

フォームのname欄は消してしまってOKです。

消したらストロングパラメーターも編集して、投稿を保存する際に

nameカラムへの保存は行わないように変更しましょう!

またtweetsテーブルからもnameカラムを削除しましょう。

その際は追加の時と同じでコマンドから削除ができます。

こちらを実行しましょう。

rails  g  migration  RemoveNameFromUsers  name : string

 

 

以上がアソシエーションの使い方でした。