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

概要

原著者の許諾を得て翻訳・公開いたします。

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メソッド群よりもよい結果が得られるかどうか」です。

ツイートより

関連記事

Ruby/Railsのプロ開発者としての5年間を振り返る(翻訳)

Rails: ActiveRecord::Relationで生SQLは避けよう(翻訳)

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ