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

概要 原著者の許諾を得て翻訳・公開いたします。 英語記事: A scope should return a scope - Andy Croll 原文公開日: 2018/10/14 著者: Andy Croll 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`(翻訳)