デフォルト順序を定義できる `default_order` をリレーションとアソシエーションに追加

rails/rails

Active Recordに #default_order クエリメソッドと default_order アソシエーションオプションが追加され、他の順序指定がない場合に適用されるデフォルト順序を定義できるようになりました。これにより、#implicit_order_column が提供していた機能がスコープとアソシエーションのレベルに拡張されます。

背景

これまでActive Recordでは、モデルレベルでの順序を default_scope { order(...) } で定義するか、アソシエーションのラムダで order を指定する方法が主流でした。しかし、どちらのアプローチも「他の順序指定がある場合はデフォルト順序を無視したい」という一般的なユースケースに対応できませんでした。default_scopeorderreorderunscope を使わなければ上書きできず、ラムダで指定した order も同様に結合されてしまいます。

#implicit_order_column はこの問題をモデルの主キー選択レベルで解決していましたが、任意のカラムや式をアソシエーションやスコープ単位で指定する手段が不足していました。本PRはRuby on Railsフォーラムでの議論(https://discuss.rubyonrails.org/t/default-order-for-relations/75554)を経て実装された変更です。

技術的な変更

default_orderMULTI_VALUE_METHODS に追加された新しい値リストであり、order_values とは独立した default_order_values として管理されます。クエリ構築時に order_values が空の場合のみ default_order_values が使用されるため、明示的な order が優先されます。

query_methods.rb に追加された #default_order#default_order! は、既存の #order / #reorder! と同じ構造に従っています。

変更後(query_methods.rb):

def default_order(*args)
  check_if_method_has_arguments!(__callee__, args) do
    sanitize_order_arguments(args)
  end
  spawn.default_order!(*args)
end

def default_order!(*args) # :nodoc:
  preprocess_order_args(args)
  self.default_order_values = args
  self
end

SQLへの適用は build_order メソッドの1行追加で実現されています。

変更後(build_order):

def build_order(arel)
  orders = order_values.compact_blank
  orders = default_order_values.compact_blank if orders.empty?
  arel.order(*orders) unless orders.empty?
end

finder_methods.rbordered_relation メソッドも同様に拡張され、order_values が空のときに default_order_valuesorder として適用してからレコードを取得します。

アソシエーション側では、collection_association.rbscope メソッドで options[:default_order] が存在する場合に default_order! を呼び出すよう変更され、has_many.rbvalid_options:default_order が追加されました。さらに、association_scope.rb ではスコープのマージ時に default_order_values も合成されるようになっています。

def scope
  scope = super
  scope.none! if null_scope?
  scope.default_order!(options[:default_order]) if options[:default_order].present?
  scope
end

設計判断

order_valuesdefault_order_values を分離して管理する設計 が採用されています。default_order_valuesorder_values に直接マージするのではなく別フィールドとして保持することで、order の存在有無を実行時に判断できます。この設計により、default_order を設定したスコープに後から order を追加した場合でも、デフォルト順序が静かに取り除かれる動作を実現しています。

アソシエーションオプションとしての利用と、クエリメソッドとしての利用の両方をサポートしている点も注目に値します。has_many :comments, default_order: :likes という宣言的な書き方と、Relation#default_order(:likes) というメソッドチェーンの書き方が同じ仕組みの上に統一されており、インターフェースの一貫性が保たれています。また、default_order_valuesMULTI_VALUE_METHODS に含まれているため、unscope(:default_order) による取り消しも可能です。

まとめ

default_order の追加により、「明示的な順序指定がなければこの順序で返す」というよく求められる挙動を、default_scope のような強制的な適用なしに宣言できるようになりました。order_valuesdefault_order_values を独立したフィールドとして管理する設計は、既存のクエリパイプラインへの影響を最小限に抑えながら、柔軟なデフォルト順序制御を実現しています。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
f84a36b9

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文(総論)、背景、技術的な変更、設計判断、まとめ(結論)の3部構成が明確に適用されており、記事の流れが非常に分かりやすいです。

カスタムMarkdown構文 ⚠ WARNING

シンタックスハイライト・GitHubリンク記法の正確性

PR番号のリンク記法がガイドラインの推奨する形式([#123](URL))とわずかに異なりますが、機能的には問題ありません。ファイル名付きシンタックスハイライトは正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

Active Recordの内部実装に関する用語を適切に使用しており、専門知識を持つエンジニアという対象読者に合致した内容です。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論→各論の構成になっており、各段落もトピックセンテンスで始まるなど、パラグラフ・ライティングの原則がよく守られています。これにより、高い可読性が確保されています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内で引用されているコードブロックは、提供されたDiff情報と完全に一致しており、変更点を正確に反映しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「default_order_values」「MULTI_VALUE_METHODS」「implicit_order_column」など、PRやRailsの文脈で使われる技術用語を正確に使用しています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

「order_valuesが空の場合にdefault_order_valuesが使われる」という説明は、Diff内の `build_order` メソッドのロジックと一致しており、技術的に正確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張(#implicit_order_columnからの拡張、フォーラムでの議論など)は、PRのDescriptionやDiff内容で裏付けられており、ハルシネーションは見られません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#39525)やファイルパス、メソッド名などの固有名詞はすべて正確に記載されています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトルはPRの主題「Add support for default order」をより具体的に説明しており、内容と完全に一致しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

PR情報に含まれない外部知識(バージョンのサポート状況やリリース日程など)の追加はなく、事実に基づいた記述に徹しています。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

「追加され」「実装された」といった過去形の表現が適切に使われており、時間的な歪曲はありません。