【Rails】モデルの関連を活用してデータを取得しよう

フィヨルドブートキャンプのコードレビューでよく指摘しているシリーズです。 以下のようなコードがあったとします。このコードは動作には問題はありませんが、Railsらしくないです。どこがおかしいでしょうか? ```ruby @blog = Blog.where(user_id: current_user.id).find(params[:id]) ``` . . . . . . . . . . . . . はい、では答え合わせです。 上のコードは、ログイン中のユーザーが書いたブログ記事の中から、`params`で指定されたidの記事を取得するコードです。 ということは、`Blog`と`User`は以下のような関連を持っていると考えるのが自然です。 ```ruby class User < ApplicationRecord has_many :blogs end class Blog < ApplicationRecord belongs_to :user end ``` モデル同士の関連を活用すれば、「ユーザーの書いたブログの一覧」は以下のように取得でます。 ```ruby current_user.blogs ``` そして、その中からidに合致する記事を見つけてくればOKです。 ```ruby @blog = current_user.blogs.find(params[:id]) ``` ## 両者の比較 以下のコードはどちらも得られる結果は同じです。 ```ruby @blog = Blog.where(user_id: current_user.id).find(params[:id]) @blog = current_user.blogs.find(params[:id]) ``` しかし、後者の方がシンプルですし、関連の概念をきちんと理解できていれば「`current_user.blogs`=ユーザーの書いたブログ」とコードを読むことができます。 ## `Blog.where(...)`のようなコードは事故が起きやすい 実務で開発するような大きなアプリケーションになってくると、`Blog.where(...)`や`User.where(...)`のようにクラス名から書き始めるデータ検索のコードを書く機会はかなり少なくなります。というのも、取得しようとしているデータは何らかのグループやユーザー等に属するものであることが多いからです。 また、`Blog.where(...)`のようなコードは「全ブログの中から条件に合致するデータを抽出する」という意味になります。しかし、これだとうっかり実装をミスったときに、見えてはいけないデータが見えてしまうセキュリティ上の事故が発生しかねません。 一方、`current_user.blogs.where(...)`のように関連を使ってデータを取得すれば、最低限「ログイン中のユーザーに紐付くブログ記事」にデータが限定されるので、実装をミスっても大事故になりにくいです。(他のユーザーのデータが意図せず見えてしまう、というような事故は起きにくい) Railsでデータを取得するコードを書くときは、「関連を活用できないか?」ということを十分吟味してからコードを書くようにしてください。 ```ruby # 関連を活用できていないコード(クラス名から始まっている) @blog = Blog.where(user_id: current_user.id).find(params[:id]) # 関連を活用しているコード(変数名から始まっている) @blog = current_user.blogs.find(params[:id]) ```