インラインパーシャルでのオブジェクトレンダリング時にローカル変数が消失するバグを修正

rails/jbuilder

Jbuilderのインラインパーシャル構文でオブジェクトをレンダリングする際、カスタムローカル変数が無視される(またはエラーになる)バグが修正されました。コレクションでは正常に動作していたものの、単一オブジェクトのレンダリングパスにのみ存在していた問題です。

背景

json.key object, partial: 'path/to/partial', as: :sym, my_local: 'value' という構文でローカル変数を渡した場合、コレクションと単一オブジェクトで挙動が一致しないという不整合が発生していました。コレクション(配列)では my_local が正しく 'value' として渡される一方、単一オブジェクトでは渡したはずの値が無視されてデフォルト値が使われたり、strict localsでデフォルト値がない場合は missing local エラーが発生したりしていました。

PRの説明によれば、この問題は #591 のパフォーマンス最適化がリグレッションを引き起こした可能性があります。#591 では reverse_merge![]= に置き換える変更が行われましたが、その際に locals キーの処理タイミングに関する副作用が生じたと考えられます。

根本原因は _set_inline_partial_render_partial_with_options の責務の重複にありました。_set_inline_partial が先に options[:locals] を設定してしまうため、_render_partial_with_options が後からローカル変数を options から取り出して locals にマージしようとした際、キーが既に存在するためスキップされていました。

技術的な変更

修正の核心は、_set_inline_partial での options[:locals] への書き込みを廃止し、object の受け渡しを options の最上位キーに移すことで、ローカル変数の組み立てを _render_partial_with_options に一本化した点にあります。

変更前:

def _set_inline_partial(name, object, options)
  # ...
  else
    _scope do
      options[:locals] = { options[:as] => object }  # locals を早期に上書き
      _render_partial_with_options options
    end
  end
end

def _render_partial_with_options(options)
  # ...
  else
    _render_partial options  # 別メソッドへの委譲
  end
end

def _render_partial(options)  # 単一オブジェクト用の分離メソッド
  options[:locals][:json] = self
  @context.render options
end

変更後:

def _set_inline_partial(name, object, options)
  # ...
  else
    _scope do
      options[options[:as]] = object  # locals ではなくオプションの最上位キーに設定
      _render_partial_with_options options
    end
  end
end

def _render_partial_with_options(options)
  # ...
  else
    options[:locals][:json] = self  # locals への書き込みはここで一元化
    @context.render options
  end
end

# _render_partial メソッドは削除

変更後は _set_inline_partialoptions[:locals] に触れなくなったため、options に含まれる my_local: 'custom' などのカスタムキーが _render_partial_with_options の処理フローで正しく locals に組み込まれます。あわせて _render_partial という中間メソッドも削除され、単一オブジェクトとコレクション以外のレンダリングパスが一本化されました。

テストでは、従来カバーされていなかった3つのケースが追加されています。

  • 単一オブジェクトをインラインパーシャルで描画するケース
  • 単一オブジェクトにローカル変数を渡すケース
  • コレクションにローカル変数を渡すケース

設計判断

ローカル変数の組み立て責務を _render_partial_with_options に集約するアプローチが採用されました。

修正以前は _set_inline_partiallocals ハッシュを生成・設定し、_render_partial_with_options がそれを参照するという分散した構造になっていました。この責務の分散がバグの温床となっていたため、_set_inline_partial はオブジェクトを options の最上位キーに置くだけに留め、locals の組み立ては _render_partial_with_options 内のみで行うよう整理されています。

PR著者は将来的な改善として _set_inline_partial メソッド自体の廃止も提案しており、locals の調整を _render_partial_with_options に完全統合することで間接参照をさらに減らせると述べています。今回の修正はその方向への第一歩と見ることができます。

まとめ

本PRは、単一オブジェクトのインラインパーシャルレンダリングでローカル変数が失われる不整合を、_set_inline_partial_render_partial_with_options の責務境界を明確化することで解消しました。中間メソッドの削除と責務の集約という設計整理が、バグ修正と同時にコードの見通しを改善しています。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
9cedf516

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

リード文(総論)→背景・技術詳細・設計判断(各論)→まとめ(結論)という「総論→各論→結論」の構成が明確に適用されています。各セクションの役割が明確で、非常に理解しやすい構成です。

カスタムMarkdown構文 ✓ PASS

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

ファイル名付きシンタックスハイライト(```ruby:ファイルパス)とGitHubのPRリンク記法([#番号](URL))が、ガイドラインに沿って正しく使用されています。

対象読者への適合性 ✓ PASS

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

Jbuilderの内部実装に関する詳細な解説であり、専門知識を持つエンジニアという対象読者に完全に適合しています。冗長な説明がなく、的確な内容です。

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

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

各セクションが総論→各論で構成され、各パラグラフもトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られています。これにより、記事の骨子を素早く把握できます。

Diff内容との照合 ✓ PASS

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

記事内で引用されているコードブロック(変更前・変更後)は、提供されたDiffの内容と完全に一致しています。メソッドの削除についても言及されており、変更点が正確に反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「インラインパーシャル」「リグレッション」「責務の重複」といった技術用語が、PRの文脈に沿って正確かつ適切に使用されています。

説明の技術的正確性 ✓ PASS

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

バグの根本原因や修正内容に関する技術的な説明は、PRのDescriptionやDiffと一致しており、論理的で正確です。

事実の突合 ✓ PASS

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

記事内のすべての主張(#591がリグレッションの可能性がある点、将来的なリファクタリング案など)は、PRのDescriptionで裏付けられており、ハルシネーション(捏造)は見られません。

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

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

PR番号(#613, #591)が正確に記載されています。

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

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

記事のタイトル「インラインパーシャルでのオブジェクトレンダリング時にローカル変数が消失するバグを修正」は、PRのタイトル「fix: Preserve locals when rendering inline partial for object」の内容を的確に要約しています。

外部知識の正確性 ✓ PASS

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

PR情報に含まれていない外部知識(バージョンのサポート状況など)の追記はなく、提供された情報源に忠実です。

時間表現の正確性 ✓ PASS

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

PR Descriptionにある「This _may_ have been a regression」という推測を、記事でも「リグレッションを引き起こした可能性があります」と正確なニュアンスで表現できています。