Tech Racho エンジニアの「?」を「!」に。
  • 開発

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`(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。