Rails: スコープはスコープを返すべき(翻訳)

概要

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

Rails: スコープはスコープを返すべき(翻訳)

RailsアプリをコーディングしていてRailsというレールに乗っている期間が長くなればなるほど、アプリを楽にメンテできるようになり、つらさが軽減されます。

レールに乗るよい方法の1つは、標準のRails APIのパターンに沿って進めることです。そうやって進めるときに自分を導いてくれるパターンの1つが、よく使われるクエリをスコープ化することです。

次のように書くのではなく

スコープ内でオブジェクトを1つ返すメソッドを書く。

class Message < ActiveRecord
  scope :sent, -> { where.not(sent_at: nil) }
  scope :recently_sent, -> { sent.order(sent_at: :desc) }
  scope :most_recently_sent, -> { recently_sent.first } # オブジェクトかnilを返す
end

常に次のように書くこと

名前付きスコープからはActiveRelationを1つ返すようにする。

class Message < ActiveRecord
  scope :sent, -> { where.not(sent_at: nil) }
  scope :recently_sent, -> { sent.order(sent_at: :desc) }

  def self.most_recently_sent
    recently_sent.first
  end
end

そうすべき理由

このように書き換えることで、モデルの使われ方を変えずにコードの構成を改善できます。

.where.orderを呼ぶとActive Relationの「スコープ」が1つ返されますが、これは別のスコープと互いにチェインできます。これによって、あらゆる名前付きスコープが互いにチェイン可能になっているこの振る舞いをメンテするときに、柔軟性と再利用性が高まります。

驚き最小の原則は、コードを編成するうえで確かなヒューリスティクスとして役立ちます。

そうすべきでない理由があるとすれば

同じことは、単にスコープ同士を注意深く扱うことでも実現できるといえばできるのですが、1つのスコープ内で.first.lastを使うときのルールというものは存在しません。

このヒューリスティクスは、自分や同僚が今後作成するであろうスコープで、コードを上手に組み立てるのにうってつけのガイドとなります。ぜひとも使いましょう。

関連記事

Rails: pluckでメモリを大幅に節約する(翻訳)

Rails: `present?`より便利なActiveSupportの`presence`(翻訳)

デザインも頼めるシステム開発会社をお探しなら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の書いた記事

BPSアドベントカレンダー

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ