概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: 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
を使うときのルールというものは存在しません。
このヒューリスティクスは、自分や同僚が今後作成するであろうスコープで、コードを上手に組み立てるのにうってつけのガイドとなります。ぜひとも使いましょう。