From 77b5ab70272c195cda5bdd4078ae4135ec8d4f72 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Thu, 8 Feb 2024 16:25:14 -0500 Subject: [PATCH] Stream Tag Builder: Support `:renderable` arguments When passed a valid `:renderable` option (like an object that responds to `#render_in`), treat that object as both the `` 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) # => ``` --- app/models/turbo/streams/tag_builder.rb | 2 ++ test/streams/streams_helper_test.rb | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/app/models/turbo/streams/tag_builder.rb b/app/models/turbo/streams/tag_builder.rb index 294c4e76..598f300f 100644 --- a/app/models/turbo/streams/tag_builder.rb +++ b/app/models/turbo/streams/tag_builder.rb @@ -271,6 +271,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 diff --git a/test/streams/streams_helper_test.rb b/test/streams/streams_helper_test.rb index e8511dfb..f4988a39 100644 --- a/test/streams/streams_helper_test.rb +++ b/test/streams/streams_helper_test.rb @@ -43,4 +43,28 @@ class Turbo::StreamsHelperTest < ActionView::TestCase 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) + + HTML + end + + class Component + extend ActiveModel::Naming + + def initialize(id:, content:) = (@id, @content = id, content) + def render_in(...) = @content + def to_key = [@id] + end + + test "supports valid :renderable option objects" do + component = Component.new(id: 1, content: "Hello, world") + + assert_dom_equal <<~HTML.strip, turbo_stream.update(component) + + HTML + end end