Rails: モデルの外では名前付きスコープだけを使おう(翻訳)

概要 原著者の許諾を得て翻訳・公開いたします。 英語記事: Only use named scopes outside models - Andy Croll 原文公開日: 2018/03/04 著者: Andy Croll Rails: モデルの外では名前付きスコープだけを使おう(翻訳) 前回の記事では#whereメソッドで「hashスタイル」を使おうというお話をいたしましたが、あまり自分が現実に使うことのなさそうなコード例でした💦。 次のようには書かないこと コントローラやビューで#whereスコープを使う。 class PostsController < ApplicationController def index @posts = Post.where(status: ‘published’) end end 次のように書くこと 名前付きスコープはモデルでのみ定義する。 class Post < ApplicationRecord scope :published, -> { where(status: ‘published’) } end コントローラなどでは次のように書く。 class PostsController < ApplicationController def index @posts = Post.published end end そうすべき理由 この手法を用いることで、コード編成が改善されます。次の2つの点において、長期的な生産性向上のために実に有用です。 その1: 自分が作り出す概念が名前として具現化されます。それ自体が明快に語ってくれる適切な名前を付けることで、あなたの同僚はもちろん、「未来の自分」にとってもしばしばありがたいものになります。 その2: 探す場所が1箇所に絞られます。スコープをモデルの外で定義していると、思いつくままのスコープやら条件やらの定義がコードベースのあちこちにばらまかれることになります。すべての条件が定義される場所がわかっていれば、リファクタリングやデータベースパフォーマンスの最適化でどこをチェックすればよいかで迷うことがなくなります。 そうすべきでない理由があるとすれば #limitや単純な#orderやページネーションに関連するスコープぐらいであれば、その場限りの特定のスコープを作ってもほとんど困ることはありません。ActiveRecord::Relationのメソッド群の構文はかなり明快だからです。 スコープに名前付けするメリットは、明快さをさらに高める場合にのみ有用です。#whereを使わないクエリの場合、シンプルなActiveRecord::Relationのメソッド群をスコープ内にラップしてもそれ以上理解しやすくなるとは限りません。 scope :by_title, -> { sort(:title) } # メリットないかも scope :by_updated_at, -> { sort(:updated_at) } # 名前ひどすぎ scope :recently_updated, -> { sort(updated_at: :desc) } # たぶんこれはやる価値あり 順序が複雑な場合や、ソート順が#whereクエリで指定される条件と強く関連している場合であれば、名前付きスコープは依然としてよい選択肢である点は覚えておくとよいでしょう #orderや#limitを使う名前付きスコープを作成するかどうかの判断に使える、うまいヒューリスティック(発見的方法)があります。「その概念には簡単に名前を付けられるかどうか」「既存のActiveRecord::Relationメソッド群よりもよい結果が得られるかどうか」です。 ツイートより そうすべき理由とそうすべきでない理由がわかりやすい / Rails: モデルの外では名前付きスコープだけを使おう(翻訳) https://t.co/RVNpx26xdP — 🍗だいしろ🐟 (@d14a) June 14, 2018 コントローラーに生のwhere出てきたら泣けるしね / “Rails: モデルの外では名前付きスコープだけを使おう(翻訳)” https://t.co/1fcfN5kUTq — Ryutaro YOSHIBA (@ryuzee) June 13, 2018 関連記事 Ruby/Railsのプロ開発者としての5年間を振り返る(翻訳) Rails: ActiveRecord::Relationで生SQLは避けよう(翻訳)