Skip to content

Commit

Permalink
Stream Tag Builder: Support :renderable arguments
Browse files Browse the repository at this point in the history
When passed a valid `:renderable` option (like an object that responds
to `#render_in`), treat that object as both the `<turbo-stream>`
element's template contents _and_ attempt to treat it as the target.

For example, consider a simplified "component" class:

```ruby
class Component
  extend ActiveModel::Naming

  def initialize(id:, content:) = (@id, @content = id, content)
  def render_in(...) = @content
  def to_key = [@id]
end

component = Component.new(id: 1, content: "Hello, world")

turbo_stream.update(component) # => <turbo-stream action="update" target="component_1"><template>Hello, world</template></turbo-stream>
```
  • Loading branch information
seanpdoyle committed Feb 8, 2024
1 parent ef4a624 commit bf65ac0
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 0 deletions.
2 changes: 2 additions & 0 deletions app/models/turbo/streams/tag_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ def action_all(name, targets, content = nil, allow_inferred_rendering: true, **r
private
def render_template(target, content = nil, allow_inferred_rendering: true, **rendering, &block)
case
when target.respond_to?(:render_in)
target.render_in(@view_context, &block)
when content.respond_to?(:render_in)
content.render_in(@view_context, &block)
when content
Expand Down
27 changes: 27 additions & 0 deletions test/streams/streams_helper_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,31 @@ class Turbo::StreamsHelperTest < ActionView::TestCase
<turbo-stream action="highlight" targets=".a-selector"><template></template></turbo-stream>
HTML
end

test "supports valid :partial option objects" do
message = Message.new(id: 1, content: "Hello, world")

assert_dom_equal <<~HTML.strip, turbo_stream.update(message)
<turbo-stream action="update" target="message_1"><template><p>Hello, world</p></template></turbo-stream>
HTML
end

test "supports valid :renderable option objects" do
component_class = Class.new do
def self.model_name
ActiveModel::Name.new(self, nil, "Component")
end
delegate :model_name, to: :class

def initialize(id:, content:) = (@id, @content = id, content)
def render_in(...) = @content
def to_key = [@id]
end

component = component_class.new(id: 1, content: "Hello, world")

assert_dom_equal <<~HTML.strip, turbo_stream.update(component)
<turbo-stream action="update" target="component_1"><template>Hello, world</template></turbo-stream>
HTML
end
end

0 comments on commit bf65ac0

Please sign in to comment.