フィヨルドブートキャンプのコードレビューでよく指摘しているシリーズです。
以下のようなコードがあったとします。このコードは動作には問題はありませんが、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])
```
ブログ