Fix yielded content rendered at wrong location with Rails form helpers#2619
Draft
joelhawksley wants to merge 1 commit intomainfrom
Draft
Fix yielded content rendered at wrong location with Rails form helpers#2619joelhawksley wants to merge 1 commit intomainfrom
joelhawksley wants to merge 1 commit intomainfrom
Conversation
When a component renders a partial that uses a Rails form helper (like form.label) with a yielding block, the yielded content was rendered outside the helper's tag instead of inside it. Root cause: form_with creates form builders with @template_object pointing to the component. When form.label calls capture through the component during partial rendering, the component's @output_buffer (set once in render_in) is stale — Rails' _run has already replaced the view context's output buffer with a fresh one for the partial. The capture reads from the wrong buffer while the block writes to the partial's buffer, causing the content to leak. Fix: Override capture in ViewComponent::Base to sync @output_buffer with view_context.output_buffer before delegating to super. Fixes #2617 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When a ViewComponent renders a partial that uses a Rails form helper (like
form.label) with a yielding block, the yielded content is rendered outside the helper's tag instead of inside it.Expected:
<label>world</label>Actual:
world <label></label>Reported in #2617 — this PR provides the fix.
Root Cause
form_withcreates form builders with@template_objectpointing to the component. When the form builder is later used inside a partial (e.g.form.label :something do ... end), it calls@template_object.capture(builder, &block)— capturing on the component's@output_buffer.However, Rails'
Template#render→_runhas already replacedview_context.@output_bufferwith a freshOutputBufferfor the partial. The compiled partial template code writes to this new buffer, while the component's@output_bufferstill references the original one set duringrender_in.This mismatch means
form.label's capture reads from an empty (stale) buffer, and the block's output leaks into the partial's main output stream instead of being wrapped by the label tag.Fix
Override
captureinViewComponent::Baseto synchronize@output_bufferwithview_context.output_bufferbefore delegating tosuper. This ensures form helpers that capture through the component use the same buffer that the block's template code writes to.Test
Adds a test case with a component that renders a partial using
form.labelwithyield, verifying the yielded content appears inside the label tag.