Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Rails: created_atやupdated_atのソートでスコープとconcernを使う(翻訳)

概要

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

日本語タイトルは内容に即したものにしました。

Rails: created_atやupdated_atのソートでスコープとconcernを使う(翻訳)

以前の記事『Rails: モデルの外では名前付きスコープだけを使おう』で、クエリAPIの呼び出しをモデルの中にとどめておくのはよいアイデアであると提案しました。Railsが提供するscopeは、常用されるクエリをカプセル化する方法のひとつです。

またRailsは、さまざまな場所で用いられる機能をグループ化する方法のひとつとしてActive Support::Concernも提供しています。concernは、Rubyの標準的なmoduleのラッパーです。

アプリケーション内の複数の場所で使いたくなることのある機能といえば、組み込みのActiveRecord::Timestampを用いて作成時や更新時でモデルをソートする機能です。

この2つを組み合わせて、アプリケーションにこの機能を追加する便利なミニライブラリを作ってみましょう。

以下のように書くよりも

orderにスコープを渡してタイムスタンプ順にソートする。

# app/controllers/books_controller.rb
class BooksController
  def index
    @books = Book.order(created_at: :asc).limit(20)
  end
end

以下のように名前付きスコープを使うとましになる。

# app/models/book.rb
class Book < ApplicationRecord
  scope :by_recently_created, -> { order(created_at: :desc) }
end
# app/controllers/books_controller.rb
class BooksController
  def index
    @books = Book.by_recently_created.limit(20)
  end
end

以下のように書く

便利なconcernを作る。

# app/models/concerns/orderable_by_timestamp.rb
module OrderableByTimestamp
  extend ActiveSupport::Concern

  included do
    scope :by_earliest_created, -> { order(created_at: :asc) }
    scope :by_recently_created, -> { order(created_at: :desc) }
    scope :by_earliest_updated, -> { order(updated_at: :asc) }
    scope :by_recently_updated, -> { order(updated_at: :desc) }
  end
end
# app/models/book.rb
class Book < ApplicationRecord
  include OrderableByTimestamp
end
# app/controllers/books_controller.rb
class BooksController
  def index
    @books = Book.by_recently_created.limit(20)
  end
end

スコープがconcernに切り出されたので、OrderableByTimestampを複数のモデルで使い回せるようになります。

そうする理由

このよくあるリファクタリングには、Railsの複数の部分が連携して機能するマジックが表れています。

これらの便利な機能を用いて、よく使う機能を1箇所に集めました。これを「コードのDRY化」と呼ぶことがあります。

そうしない理由があるとすれば

そこそこ一般的な4つのスコープを複数のモデルにincludeしても、それらの一部しか使われないのであれば、モデルが不必要に肥大する可能性があります。このような理由で、concernのコードはできるだけ小さくしておく必要があります。

謝意

Danは、私たちが手掛けている以下のアプリケーションにこのパターンを取り入れてくれました。

関連記事

Rails: URLヘルパーをビューやコントローラ以外の場所で使う(翻訳)


CONTACT

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