`ActiveModel::Conversion`にデフォルトの`#render_in`実装を追加

rails/rails

ActiveModel::Conversionモジュールに#render_inのデフォルト実装が追加され、Active ModelおよびActive Recordのインスタンスがrenderメソッドに渡された際の挙動をモデル側から制御できるようになりました。これにより、ViewComponentなどのサードパーティビューシステムとのインテグレーションポイントがActive Modelレベルで統一されます。

背景

#render_inメソッドは#36388および#37919でAction Viewに導入され、オブジェクトが自身のレンダリングをビューコンテキストに委ねる拡張ポイントとして機能してきました。続く#50623では、locals:やブロックといった呼び出し元のオプションを#render_inに転送する対応が行われています。

しかし、#render_inはあくまで「オプションのインターフェース」であり、ActiveModel::Conversionincludeしたモデルはデフォルトでは#render_inを持ちませんでした。そのため、render personのような呼び出しではto_partial_path経由のパス解決が内部的に行われるのみで、モデル側がレンダリング処理をカスタマイズする標準的な経路がありませんでした。本PR #57349はこの空白を埋め、Active Modelをincludeするすべてのクラスにデフォルトの#render_in実装を提供します。

技術的な変更

ActiveModel::Conversionのインスタンスメソッドとして#render_inが追加され、to_partial_pathobject: selfを組み合わせたパーシャルレンダリングがデフォルト実装となりました。

追加されたメソッド(activemodel/lib/active_model/conversion.rb):

def render_in(view_context, **options, &block)
  view_context.render(partial: to_partial_path, object: self, **options, &block)
end

シグネチャは#50623で確立されたrender_in(view_context, **options, &block)に準拠しており、呼び出し元から渡されたlocals:などのオプションとブロックがそのままパーシャルレンダリングに引き継がれます。たとえば次のような呼び出しがすべて意図通りに動作します:

person = Person.new(name: "Ralph")

render person                                       # => "Ralph"
render person, shout: true                          # => "RALPH"
render renderable: person                           # => "Ralph"
render renderable: person, locals: { shout: true }  # => "RALPH"

Active Model Lintテストへの追加(activemodel/lib/active_model/lint.rb):

def test_render_in
  view_context = Object.new
  def view_context.render(...)
    ""
  end
  assert_respond_to model, :render_in
  assert_kind_of String, model.render_in(view_context)
end

#render_inへの応答と文字列の返却が、Active ModelのLintテストに正式な要件として組み込まれました。これにより、ActiveModel::Lint::Testsを使ってモデルの適合性を検証しているプロジェクトは、#render_inの存在も自動的に検証されます。

また、ログサブスクライバーのテスト(actionview/test/template/log_subscriber_test.rb)では期待するログ行数が1から2に変更されており、#render_in経由のレンダリングによってRendering Customerのログエントリが新たに出力されることが確認されています。

設計判断

既存のto_partial_pathとの関係を保持したデフォルト実装 が採用されました。

新しいデフォルト実装はpartial: to_partial_pathobject: selfを組み合わせるだけで、従来のrender personが内部で行っていた処理と等価です。これにより、既存のモデルを使用するアプリケーションは#render_inの追加によって挙動が変わりません。モデル側でカスタムの#render_inを定義している場合はそちらが優先されるため、オーバーライドによるカスタマイズの自由度も維持されています。

#46202ではコントローラやビュー側にrenderer_forのような選択ロジックを持たせる案も議論されていましたが、本PRはその方向には進まず、モデル自身がレンダリング方法を提供するという現行の#render_inの設計を踏襲しています。optionsとブロックの透過的な転送を標準実装に含めることで、locals:shout: trueのようなコールサイトの引数がパーシャルまで届く設計になっています。

まとめ

本PRは、Action Viewの内部処理として暗黙的に行われていた「to_partial_pathを使ったパーシャルレンダリング」を、Active Modelの公開インターフェースとして明示的に定義した変更です。デフォルト実装を提供しながら後方互換性を保ち、かつLintテストへの追加によってActive Modelの公式な契約としての地位を確立したことで、ViewComponentなどのビューシステムがモデルレベルでのレンダリングカスタマイズを標準的な経路で実装できる基盤が整いました。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
51b0826c

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

リード文(総論)→背景・技術詳細・設計判断(各論)→まとめ(結論)という3部構成が明確に適用されており、非常に分かりやすい構成です。

カスタムMarkdown構文 ✓ PASS

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

ファイル名付きシンタックスハイライト(```ruby:path```)やPR番号のリンク記法([#123](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

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

Active ModelやAction Viewの内部挙動に関する内容であり、専門知識を持つエンジニアという対象読者に適合しています。

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

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

各セクション、各パラグラフが「総論→各論」の構造で書かれており、トピックセンテンスが明確です。段落の長さも適切で、非常に可読性が高いです。

Diff内容との照合 ✓ PASS

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

記事内で引用されている`activemodel/lib/active_model/conversion.rb`と`activemodel/lib/active_model/lint.rb`のコードは、Diffと完全に一致しています。また、テストログの行数変更に関する言及も正確です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`ActiveModel::Conversion`, `#render_in`, `to_partial_path`, `Lintテスト`などの技術用語が、文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

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

「既存の挙動を変えないデフォルト実装」である点や、「Lintテストの要件に組み込まれた」点など、変更の技術的な内容と影響が正確に説明されています。

事実の突合 ✓ PASS

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

記事内の主張はすべてPRのDescriptionやDiff内容で裏付けられています。特に「設計判断」セクションでは、過去のPR(#46202)との関連性をPR情報から読み解いており、ハルシネーションは見られません。

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

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

PR番号(#57349, #36388, #50623など)はすべて正確に記載・リンクされています。

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

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

記事のタイトルはPRのタイトルと完全に一致しており、内容を的確に表現しています。

外部知識の正確性 ✓ PASS

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

バージョン情報やリリース予定など、PR情報にない外部知識の記述は見られず、事実に忠実です。

時間表現の正確性 ✓ PASS

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

「〜が追加され」「〜となりました」といった表現が、PRによる変更内容を正確な時間感覚で記述しています。