turbo_stream tag builder: support :partial with block - #701
Merged
jorgemanrubia merged 1 commit intoMar 2, 2025
Conversation
The Background
---
Consider an application with a shared `application/flash` partial that
accepts its message as a partial-local assignment:
```erb
<%# app/views/application/_flash.html.erb %>
<p role="alert"><%= message %></p>
```
Also consider an `application/layout.turbo_stream.erb` template for
appending the `Flash` messages to a element with `[id="flashes"]`:
```erb
<%# app/views/layouts/application.turbo_stream.erb %>
<% flash.each do |name, message| %>
<%= turbo_stream.append "flashes", partial: "application/flash", locals: { message: message } %>
<% end %>
```
This works as you'd expect, since the `:partial` and `:locals` keyword
arguments are forwarded along to the underlying `render` call.
The Scenario
---
Now consider that the `application/flash` message changed its interface
to expect the `message` as block content yielded to the partial instead
of an assignment to the `:locals` options:
```diff
<%# app/views/application/_flash.html.erb %>
-<p role="alert"><%= message %></p>
+<p role="alert"><%= yield %></p>
```
The `layouts/application.turbo_stream.erb` template would need to change
as well:
```diff
<%# app/views/layouts/application.turbo_stream.erb %>
<% flash.each do |name, message| %>
- <%= turbo_stream.append "flashes", partial: "application/flash", locals: { message: message } %>
+ <%= turbo_stream.append "flashes", partial: "application/flash" do %>
+ <span style="color: red"><%= message %></span>
+ <%= end %>
<% end %>
```
The Problem
---
This style of invocation of `turbo_stream.append` does not work the same
as if it were passed a block of content generated by calling `render`
with the same keywords.
The presence of a `&block` argument triggers an entirely separate code
path than the presence of the `**rendering` keywords.
To work around this issue, you'd have to capture the rendering
separately:
```diff
<%# app/views/layouts/application.turbo_stream.erb %>
<% flash.each do |name, message| %>
- <%= turbo_stream.append "flashes", partial: "application/flash", locals: { message: message } %>
+ <% content = capture do %>
+ <%= render partial: "application/flash" do %>
+ <span style="color: red"><%= message %></span>
+ <% end %>
+ <% end %>
+
+ <%= turbo_stream.append "flashes", content %>
<% end %>
```
The Proposal
---
This commit alters the tag builder's decision making process to
incorporate a check for a combination of both a `&block` and `:partial`
or `:layout` keyword arguments.
seanpdoyle
force-pushed
the
turbo_stream_builder_block
branch
from
March 2, 2025 21:28
ed14a32 to
7920f63
Compare
jorgemanrubia
approved these changes
Mar 2, 2025
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.
The Background
Consider an application with a shared
application/flashpartial that accepts its message as a partial-local assignment:Also consider an
application/layout.turbo_stream.erbtemplate for appending theFlashmessages to a element with[id="flashes"]:This works as you'd expect, since the
:partialand:localskeyword arguments are forwarded along to the underlyingrendercall.The Scenario
Now consider that the
application/flashmessage changed its interface to expect themessageas block content yielded to the partial instead of an assignment to the:localsoptions:The
layouts/application.turbo_stream.erbtemplate would need to change as well:The Problem
This style of invocation of
turbo_stream.appenddoes not work the same as if it were passed a block of content generated by callingrenderwith the same keywords.The presence of a
&blockargument triggers an entirely separate code path than the presence of the**renderingkeywords.To work around this issue, you'd have to capture the rendering separately:
The Proposal
This commit alters the tag builder's decision making process to incorporate a check for a combination of both a
&blockand:partialor:layoutkeyword arguments.