From 05d4f62d06ffe8fc26eeee003e5d99abf7622f07 Mon Sep 17 00:00:00 2001 From: Francesco Kirchhoff Date: Fri, 25 Sep 2026 09:58:24 +0100 Subject: [PATCH 1/3] Engine: dispatch on the value when resolving a tag helper's implicit attribute turbo_frame_tag and image_tag choose how to build their id and src from the value's class at render time. Resolving them into markup chose statically, from the shape of the argument, so a String id reached dom_id and raised on to_key, and an Active Storage blob reached image_path and resolved to "". The type does not have to be known at compile time. Both now emit the branch the helper itself performs, binding the argument once so an expression with side effects still evaluates a single time. A literal argument still folds to static markup, and a literal dom_id call is still passed through, so the cases the resolution exists for are unchanged. --- src/analyze/action_view/image_tag.c | 27 +++++++++++++++++++ src/analyze/action_view/tag_helpers.c | 3 ++- src/analyze/action_view/turbo_frame_tag.c | 19 +++++++------ .../action_view/turbo_frame_tag_test.rb | 7 +++++ ...fc9af-ef4af315cb33925c38d24ea3c2e8a1cd.txt | 2 +- ...dd4c8-ef4af315cb33925c38d24ea3c2e8a1cd.txt | 2 +- ...ource_f25e3c1ce03e4a2b7484fed0fe7a28f2.txt | 2 +- ...local_b752f5c855f26434c7a0ebf09268b407.txt | 6 +++++ ...local_ee5293d1659c999ab179369491fae970.txt | 5 ++++ 9 files changed, 59 insertions(+), 14 deletions(-) create mode 100644 test/snapshots/engine/action_view/turbo_frame_tag_test/test_0009_turbo_frame_tag_with_a_string_id_held_in_a_local_b752f5c855f26434c7a0ebf09268b407.txt create mode 100644 test/snapshots/engine/action_view/turbo_frame_tag_test/test_0009_turbo_frame_tag_with_a_string_id_held_in_a_local_ee5293d1659c999ab179369491fae970.txt diff --git a/src/analyze/action_view/image_tag.c b/src/analyze/action_view/image_tag.c index b83844ccf..aac5720a1 100644 --- a/src/analyze/action_view/image_tag.c +++ b/src/analyze/action_view/image_tag.c @@ -34,6 +34,33 @@ bool image_tag_source_is_url(const char* source, size_t length) { return false; } +char* wrap_in_image_source_dispatch( + const char* source, + size_t source_length, + const char* path_options, + hb_allocator_T* allocator +) { + hb_buffer_T buffer; + hb_buffer_init(&buffer, source_length + 160, allocator); + + hb_buffer_append(&buffer, "("); + hb_buffer_append_with_length(&buffer, source, source_length); + hb_buffer_append(&buffer, ").then { |value| value.is_a?(String) || value.is_a?(Symbol)"); + hb_buffer_append(&buffer, " ? image_path(value"); + + if (path_options && strlen(path_options) > 0) { + hb_buffer_append(&buffer, ", "); + hb_buffer_append(&buffer, path_options); + } + + hb_buffer_append(&buffer, ") : polymorphic_url(value) }"); + + char* result = hb_allocator_strdup(allocator, hb_buffer_value(&buffer)); + hb_buffer_free(&buffer); + + return result; +} + char* wrap_in_image_path( const char* source, size_t source_length, diff --git a/src/analyze/action_view/tag_helpers.c b/src/analyze/action_view/tag_helpers.c index 183d9bc43..2eba493c4 100644 --- a/src/analyze/action_view/tag_helpers.c +++ b/src/analyze/action_view/tag_helpers.c @@ -36,6 +36,7 @@ extern bool javascript_include_tag_source_is_url(const char*, size_t); extern bool detect_image_tag(pm_call_node_t*, pm_parser_t*); extern char* extract_image_tag_src(pm_call_node_t*, pm_parser_t*, hb_allocator_T*); extern char* wrap_in_image_path(const char*, size_t, const char*, hb_allocator_T*); +extern char* wrap_in_image_source_dispatch(const char*, size_t, const char*, hb_allocator_T*); extern bool image_tag_source_is_url(const char*, size_t); extern bool detect_stylesheet_link_tag(pm_call_node_t*, pm_parser_t*); extern char* wrap_in_stylesheet_path(const char*, size_t, const char*, hb_allocator_T*); @@ -850,7 +851,7 @@ static AST_NODE_T* transform_tag_helper_with_attributes( source_attribute_value = wrap_in_image_path(quoted_source, quoted_length, path_options, allocator); hb_allocator_dealloc(allocator, quoted_source); } else if (!source_is_string && !is_url && !source_is_path_helper) { - source_attribute_value = wrap_in_image_path(source_value, source_length, path_options, allocator); + source_attribute_value = wrap_in_image_source_dispatch(source_value, source_length, path_options, allocator); } AST_HTML_ATTRIBUTE_NODE_T* source_attribute = diff --git a/src/analyze/action_view/turbo_frame_tag.c b/src/analyze/action_view/turbo_frame_tag.c index 7236d31a2..240dafe88 100644 --- a/src/analyze/action_view/turbo_frame_tag.c +++ b/src/analyze/action_view/turbo_frame_tag.c @@ -1,4 +1,5 @@ #include "../../include/lib/hb_allocator.h" +#include "../../include/lib/hb_buffer.h" #include #include @@ -36,18 +37,16 @@ char* extract_turbo_frame_tag_id(pm_call_node_t* call_node, pm_parser_t* parser, } } - const char* prefix = "dom_id("; - const char* suffix = ")"; + hb_buffer_T buffer; + hb_buffer_init(&buffer, source_length + 128, allocator); - size_t prefix_length = strlen(prefix); - size_t suffix_length = strlen(suffix); - size_t total_length = prefix_length + source_length + suffix_length; - char* result = hb_allocator_alloc(allocator, total_length + 1); + hb_buffer_append(&buffer, "("); + hb_buffer_append_with_length(&buffer, source, source_length); + hb_buffer_append(&buffer, ").then { |value| value.respond_to?(:to_key) || value.is_a?(Class)"); + hb_buffer_append(&buffer, " ? dom_id(value) : value.to_s }"); - memcpy(result, prefix, prefix_length); - memcpy(result + prefix_length, source, source_length); - memcpy(result + prefix_length + source_length, suffix, suffix_length); - result[total_length] = '\0'; + char* result = hb_allocator_strdup(allocator, hb_buffer_value(&buffer)); + hb_buffer_free(&buffer); return result; } diff --git a/test/engine/action_view/turbo_frame_tag_test.rb b/test/engine/action_view/turbo_frame_tag_test.rb index 6cc0db74b..15f14938a 100644 --- a/test/engine/action_view/turbo_frame_tag_test.rb +++ b/test/engine/action_view/turbo_frame_tag_test.rb @@ -49,6 +49,13 @@ class TurboFrameTagTest < Minitest::Spec test "turbo_frame_tag with data attributes" do assert_optimized_snapshot('<%= turbo_frame_tag "tray", data: { controller: "frame" } do %>Content<% end %>') end + + test "turbo_frame_tag with a string id held in a local" do + assert_optimized_snapshot( + "<%= turbo_frame_tag frame_id do %>Content<% end %>", + { frame_id: "post_1" } + ) + end end end end diff --git a/test/snapshots/analyze/action_view/tag_helper/turbo_frame_tag_test/test_0011_turbo_frame_tag_with_model_wraps_in_dom_id_6668f957e9b3270e6903c501660fc9af-ef4af315cb33925c38d24ea3c2e8a1cd.txt b/test/snapshots/analyze/action_view/tag_helper/turbo_frame_tag_test/test_0011_turbo_frame_tag_with_model_wraps_in_dom_id_6668f957e9b3270e6903c501660fc9af-ef4af315cb33925c38d24ea3c2e8a1cd.txt index 5c416a147..4cb4b6395 100644 --- a/test/snapshots/analyze/action_view/tag_helper/turbo_frame_tag_test/test_0011_turbo_frame_tag_with_model_wraps_in_dom_id_6668f957e9b3270e6903c501660fc9af-ef4af315cb33925c38d24ea3c2e8a1cd.txt +++ b/test/snapshots/analyze/action_view/tag_helper/turbo_frame_tag_test/test_0011_turbo_frame_tag_with_model_wraps_in_dom_id_6668f957e9b3270e6903c501660fc9af-ef4af315cb33925c38d24ea3c2e8a1cd.txt @@ -30,7 +30,7 @@ options: {action_view_helpers: true} │ │ ├── open_quote: ∅ │ │ ├── children: (1 item) │ │ │ └── @ RubyLiteralNode (location: (1:20)-(1:24)) - │ │ │ └── content: "dom_id(post)" + │ │ │ └── content: "(post).then { |value| value.respond_to?(:to_key) || value.is_a?(Class) ? dom_id(value) : value.to_s }" │ │ │ │ │ ├── close_quote: ∅ │ │ └── quoted: true diff --git a/test/snapshots/analyze/action_view/tag_helper/turbo_frame_tag_test/test_0012_turbo_frame_tag_with_instance_variable_wraps_in_dom_id_8c2535a5f80133daa8817d2bdfcdd4c8-ef4af315cb33925c38d24ea3c2e8a1cd.txt b/test/snapshots/analyze/action_view/tag_helper/turbo_frame_tag_test/test_0012_turbo_frame_tag_with_instance_variable_wraps_in_dom_id_8c2535a5f80133daa8817d2bdfcdd4c8-ef4af315cb33925c38d24ea3c2e8a1cd.txt index 8bd62a098..b82d3dc44 100644 --- a/test/snapshots/analyze/action_view/tag_helper/turbo_frame_tag_test/test_0012_turbo_frame_tag_with_instance_variable_wraps_in_dom_id_8c2535a5f80133daa8817d2bdfcdd4c8-ef4af315cb33925c38d24ea3c2e8a1cd.txt +++ b/test/snapshots/analyze/action_view/tag_helper/turbo_frame_tag_test/test_0012_turbo_frame_tag_with_instance_variable_wraps_in_dom_id_8c2535a5f80133daa8817d2bdfcdd4c8-ef4af315cb33925c38d24ea3c2e8a1cd.txt @@ -28,7 +28,7 @@ options: {action_view_helpers: true} │ │ ├── open_quote: ∅ │ │ ├── children: (1 item) │ │ │ └── @ RubyLiteralNode (location: (1:20)-(1:25)) - │ │ │ └── content: "dom_id(@post)" + │ │ │ └── content: "(@post).then { |value| value.respond_to?(:to_key) || value.is_a?(Class) ? dom_id(value) : value.to_s }" │ │ │ │ │ ├── close_quote: ∅ │ │ └── quoted: true diff --git a/test/snapshots/engine/action_view/image_tag_test/test_0006_image_tag_with_ruby_expression_source_f25e3c1ce03e4a2b7484fed0fe7a28f2.txt b/test/snapshots/engine/action_view/image_tag_test/test_0006_image_tag_with_ruby_expression_source_f25e3c1ce03e4a2b7484fed0fe7a28f2.txt index d831338f1..2e108055e 100644 --- a/test/snapshots/engine/action_view/image_tag_test/test_0006_image_tag_with_ruby_expression_source_f25e3c1ce03e4a2b7484fed0fe7a28f2.txt +++ b/test/snapshots/engine/action_view/image_tag_test/test_0006_image_tag_with_ruby_expression_source_f25e3c1ce03e4a2b7484fed0fe7a28f2.txt @@ -2,5 +2,5 @@ source: "Engine::ActionView::ImageTagTest#test_0006_image_tag with ruby expression source" input: "{source: \"<%= image_tag user_avatar %>\", options: {visitors: [#], locals: {user_avatar: \"http://example.com/avatar.png\"}}}" --- -_buf = ::String.new; _buf << ''.freeze; +_buf = ::String.new; _buf << ''.freeze; _buf.to_s diff --git a/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0009_turbo_frame_tag_with_a_string_id_held_in_a_local_b752f5c855f26434c7a0ebf09268b407.txt b/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0009_turbo_frame_tag_with_a_string_id_held_in_a_local_b752f5c855f26434c7a0ebf09268b407.txt new file mode 100644 index 000000000..4889922f2 --- /dev/null +++ b/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0009_turbo_frame_tag_with_a_string_id_held_in_a_local_b752f5c855f26434c7a0ebf09268b407.txt @@ -0,0 +1,6 @@ +--- +source: "Engine::ActionView::TurboFrameTagTest#test_0009_turbo_frame_tag with a string id held in a local" +input: "{source: \"<%= turbo_frame_tag frame_id do %>Content<% end %>\", options: {visitors: [#], locals: {frame_id: \"post_1\"}}}" +--- +_buf = ::String.new; _buf << 'Content'.freeze; +_buf.to_s diff --git a/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0009_turbo_frame_tag_with_a_string_id_held_in_a_local_ee5293d1659c999ab179369491fae970.txt b/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0009_turbo_frame_tag_with_a_string_id_held_in_a_local_ee5293d1659c999ab179369491fae970.txt new file mode 100644 index 000000000..45615c19e --- /dev/null +++ b/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0009_turbo_frame_tag_with_a_string_id_held_in_a_local_ee5293d1659c999ab179369491fae970.txt @@ -0,0 +1,5 @@ +--- +source: "Engine::ActionView::TurboFrameTagTest#test_0009_turbo_frame_tag with a string id held in a local" +input: "{source: \"<%= turbo_frame_tag frame_id do %>Content<% end %>\", locals: {frame_id: \"post_1\"}, options: {action_view_helpers: true}}" +--- +Content \ No newline at end of file From fc86bbde11c2547d59eb4c64e69f82bcf525a1a8 Mon Sep 17 00:00:00 2001 From: Francesco Kirchhoff Date: Fri, 25 Sep 2026 10:26:45 +0100 Subject: [PATCH 2/3] Rewriter: follow the dispatch when rewriting a tag helper to HTML The rewriter reads the same resolved attribute as the compiler, so its output moves with it. The expectations it held described the guess: an Active Storage source rewritten to image_path resolves to "", which is the bug this fixes, written into a template rather than into compiled output. --- .../rewriter/test/action-view-tag-helper-to-html.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/packages/rewriter/test/action-view-tag-helper-to-html.test.ts b/javascript/packages/rewriter/test/action-view-tag-helper-to-html.test.ts index 8a9921bdd..294446923 100644 --- a/javascript/packages/rewriter/test/action-view-tag-helper-to-html.test.ts +++ b/javascript/packages/rewriter/test/action-view-tag-helper-to-html.test.ts @@ -829,9 +829,9 @@ describe("ActionViewTagHelperToHTMLRewriter", () => { ) }) - test("image_tag with ruby expression source wraps in image_path", () => { + test("image_tag with ruby expression source dispatches on the value", () => { expect(transform('<%= image_tag user.avatar %>')).toBe( - '' + '' ) }) @@ -859,9 +859,9 @@ describe("ActionViewTagHelperToHTMLRewriter", () => { ) }) - test("image_tag with instance variable method wraps in image_path", () => { + test("image_tag with instance variable method dispatches on the value", () => { expect(transform('<%= image_tag @post.cover_image %>')).toBe( - '' + '' ) }) From 63c6ddbb9bd223571bca949ba26d3eba7ca81459 Mon Sep 17 00:00:00 2001 From: Francesco Kirchhoff Date: Mon, 26 Oct 2026 01:12:35 +0000 Subject: [PATCH 3/3] Engine: honor every id passed to turbo_frame_tag turbo_frame_tag only read its first argument, so `turbo_frame_tag record, "notes"` rendered `post_1` instead of `notes_post_1`. Read every positional id and emit the same dispatch the helper performs: literal ids join statically, anything else becomes `ids.first.respond_to?(:to_key) || is_a?(Class) ? dom_id(*ids) : ids.join("_")`. Co-Authored-By: Claude Sonnet 5.5 --- src/analyze/action_view/tag_helpers.c | 5 +- src/analyze/action_view/turbo_frame_tag.c | 97 +++++++++++++++++++ .../action_view/turbo_frame_tag_test.rb | 11 +++ ...local_f99c1ef9dfa45cb9bb888bdeb9a0fecc.txt | 5 + ...local_fb07e8823d47b7f4618f7f2f56c6fec8.txt | 6 ++ ..._them_13d15ed6e517443019e4bac66bf642f0.txt | 5 + ..._them_c05c5d47b392973f974757e1d15aa2ab.txt | 5 + 7 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 test/snapshots/engine/action_view/turbo_frame_tag_test/test_0010_turbo_frame_tag_with_a_string_prefix_and_a_string_id_held_in_a_local_f99c1ef9dfa45cb9bb888bdeb9a0fecc.txt create mode 100644 test/snapshots/engine/action_view/turbo_frame_tag_test/test_0010_turbo_frame_tag_with_a_string_prefix_and_a_string_id_held_in_a_local_fb07e8823d47b7f4618f7f2f56c6fec8.txt create mode 100644 test/snapshots/engine/action_view/turbo_frame_tag_test/test_0011_turbo_frame_tag_with_literal_ids_joins_them_13d15ed6e517443019e4bac66bf642f0.txt create mode 100644 test/snapshots/engine/action_view/turbo_frame_tag_test/test_0011_turbo_frame_tag_with_literal_ids_joins_them_c05c5d47b392973f974757e1d15aa2ab.txt diff --git a/src/analyze/action_view/tag_helpers.c b/src/analyze/action_view/tag_helpers.c index 2eba493c4..cc4d4704a 100644 --- a/src/analyze/action_view/tag_helpers.c +++ b/src/analyze/action_view/tag_helpers.c @@ -29,6 +29,7 @@ extern char* wrap_in_url_for(const char*, size_t, hb_allocator_T*); extern char* extract_link_to_href(pm_call_node_t*, pm_parser_t*, hb_allocator_T*); extern bool detect_turbo_frame_tag(pm_call_node_t*, pm_parser_t*); extern char* extract_turbo_frame_tag_id(pm_call_node_t*, pm_parser_t*, hb_allocator_T*); +extern bool turbo_frame_tag_id_is_static(pm_call_node_t*); extern bool detect_javascript_include_tag(pm_call_node_t*, pm_parser_t*); extern char* extract_javascript_include_tag_src(pm_call_node_t*, pm_parser_t*, hb_allocator_T*); extern char* wrap_in_javascript_path(const char*, size_t, const char*, hb_allocator_T*); @@ -761,7 +762,7 @@ static AST_NODE_T* transform_tag_helper_with_attributes( pm_node_t* first_argument = parse_context->info->call_node->arguments->arguments.nodes[0]; position_T id_start, id_end; prism_node_location_to_positions(&first_argument->location, parse_context, &id_start, &id_end); - bool id_is_ruby_expression = (first_argument->type != PM_STRING_NODE && first_argument->type != PM_SYMBOL_NODE); + bool id_is_ruby_expression = !turbo_frame_tag_id_is_static(parse_context->info->call_node); AST_HTML_ATTRIBUTE_NODE_T* id_attribute = id_is_ruby_expression ? create_html_attribute_with_ruby_literal("id", id_value, id_start, id_end, allocator) @@ -1416,7 +1417,7 @@ static AST_NODE_T* transform_erb_block_to_tag_helper( pm_node_t* first_argument = parse_context->info->call_node->arguments->arguments.nodes[0]; position_T id_start, id_end; prism_node_location_to_positions(&first_argument->location, parse_context, &id_start, &id_end); - bool id_is_ruby_expression = (first_argument->type != PM_STRING_NODE && first_argument->type != PM_SYMBOL_NODE); + bool id_is_ruby_expression = !turbo_frame_tag_id_is_static(parse_context->info->call_node); AST_HTML_ATTRIBUTE_NODE_T* id_attribute = id_is_ruby_expression ? create_html_attribute_with_ruby_literal("id", id_value, id_start, id_end, allocator) diff --git a/src/analyze/action_view/turbo_frame_tag.c b/src/analyze/action_view/turbo_frame_tag.c index 240dafe88..aaedf57d6 100644 --- a/src/analyze/action_view/turbo_frame_tag.c +++ b/src/analyze/action_view/turbo_frame_tag.c @@ -5,12 +5,94 @@ #include #include +static bool turbo_frame_tag_literal_id(pm_node_t* node, const char** source, size_t* length) { + if (node->type == PM_STRING_NODE) { + pm_string_node_t* string_node = (pm_string_node_t*) node; + *source = (const char*) pm_string_source(&string_node->unescaped); + *length = pm_string_length(&string_node->unescaped); + + return true; + } + + if (node->type == PM_SYMBOL_NODE) { + pm_symbol_node_t* symbol_node = (pm_symbol_node_t*) node; + *source = (const char*) pm_string_source(&symbol_node->unescaped); + *length = pm_string_length(&symbol_node->unescaped); + + return true; + } + + return false; +} + +// `turbo_frame_tag *ids` is `dom_id(*ids)` when the first id is a record or Class, `ids.join("_")` otherwise. +static char* extract_turbo_frame_tag_ids( + pm_arguments_node_t* arguments, + size_t count, + pm_parser_t* parser, + hb_allocator_T* allocator +) { + (void) parser; + + hb_buffer_T buffer; + hb_buffer_init(&buffer, 128, allocator); + + bool all_literal = true; + + for (size_t index = 0; index < count; index++) { + const char* literal = NULL; + size_t literal_length = 0; + + if (!turbo_frame_tag_literal_id(arguments->arguments.nodes[index], &literal, &literal_length)) { + all_literal = false; + break; + } + + if (index > 0) { hb_buffer_append(&buffer, "_"); } + hb_buffer_append_with_length(&buffer, literal, literal_length); + } + + if (!all_literal) { + hb_buffer_clear(&buffer); + hb_buffer_append(&buffer, "["); + + for (size_t index = 0; index < count; index++) { + pm_node_t* node = arguments->arguments.nodes[index]; + + if (index > 0) { hb_buffer_append(&buffer, ", "); } + hb_buffer_append_with_length(&buffer, (const char*) node->location.start, node->location.end - node->location.start); + } + + hb_buffer_append(&buffer, "].then { |ids| ids.first.respond_to?(:to_key) || ids.first.is_a?(Class)"); + hb_buffer_append(&buffer, " ? dom_id(*ids) : ids.join(\"_\") }"); + } + + char* result = hb_allocator_strdup(allocator, hb_buffer_value(&buffer)); + hb_buffer_free(&buffer); + + return result; +} + char* extract_turbo_frame_tag_id(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) { if (!call_node || !call_node->arguments) { return NULL; } pm_arguments_node_t* arguments = call_node->arguments; if (!arguments->arguments.size) { return NULL; } + size_t positional_count = 0; + + for (size_t index = 0; index < arguments->arguments.size; index++) { + pm_node_type_t type = arguments->arguments.nodes[index]->type; + + if (type == PM_KEYWORD_HASH_NODE || type == PM_SPLAT_NODE) { break; } + + positional_count++; + } + + if (positional_count == 0) { return NULL; } + + if (positional_count > 1) { return extract_turbo_frame_tag_ids(arguments, positional_count, parser, allocator); } + pm_node_t* first_argument = arguments->arguments.nodes[0]; if (first_argument->type == PM_STRING_NODE) { @@ -50,3 +132,18 @@ char* extract_turbo_frame_tag_id(pm_call_node_t* call_node, pm_parser_t* parser, return result; } + +bool turbo_frame_tag_id_is_static(pm_call_node_t* call_node) { + if (!call_node || !call_node->arguments) { return false; } + + pm_arguments_node_t* arguments = call_node->arguments; + + for (size_t index = 0; index < arguments->arguments.size; index++) { + pm_node_t* node = arguments->arguments.nodes[index]; + + if (node->type == PM_KEYWORD_HASH_NODE || node->type == PM_SPLAT_NODE) { break; } + if (node->type != PM_STRING_NODE && node->type != PM_SYMBOL_NODE) { return false; } + } + + return true; +} diff --git a/test/engine/action_view/turbo_frame_tag_test.rb b/test/engine/action_view/turbo_frame_tag_test.rb index 15f14938a..86270d250 100644 --- a/test/engine/action_view/turbo_frame_tag_test.rb +++ b/test/engine/action_view/turbo_frame_tag_test.rb @@ -56,6 +56,17 @@ class TurboFrameTagTest < Minitest::Spec { frame_id: "post_1" } ) end + + test "turbo_frame_tag with a string prefix and a string id held in a local" do + assert_optimized_snapshot( + '<%= turbo_frame_tag "notes", frame_id do %>Content<% end %>', + { frame_id: "post_1" } + ) + end + + test "turbo_frame_tag with literal ids joins them" do + assert_optimized_snapshot('<%= turbo_frame_tag "notes", :list %>') + end end end end diff --git a/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0010_turbo_frame_tag_with_a_string_prefix_and_a_string_id_held_in_a_local_f99c1ef9dfa45cb9bb888bdeb9a0fecc.txt b/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0010_turbo_frame_tag_with_a_string_prefix_and_a_string_id_held_in_a_local_f99c1ef9dfa45cb9bb888bdeb9a0fecc.txt new file mode 100644 index 000000000..3b85f6a2f --- /dev/null +++ b/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0010_turbo_frame_tag_with_a_string_prefix_and_a_string_id_held_in_a_local_f99c1ef9dfa45cb9bb888bdeb9a0fecc.txt @@ -0,0 +1,5 @@ +--- +source: "Engine::ActionView::TurboFrameTagTest#test_0010_turbo_frame_tag with a string prefix and a string id held in a local" +input: "{source: \"<%= turbo_frame_tag \\\"notes\\\", frame_id do %>Content<% end %>\", locals: {frame_id: \"post_1\"}, options: {action_view_helpers: true}}" +--- +Content \ No newline at end of file diff --git a/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0010_turbo_frame_tag_with_a_string_prefix_and_a_string_id_held_in_a_local_fb07e8823d47b7f4618f7f2f56c6fec8.txt b/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0010_turbo_frame_tag_with_a_string_prefix_and_a_string_id_held_in_a_local_fb07e8823d47b7f4618f7f2f56c6fec8.txt new file mode 100644 index 000000000..b03b4632b --- /dev/null +++ b/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0010_turbo_frame_tag_with_a_string_prefix_and_a_string_id_held_in_a_local_fb07e8823d47b7f4618f7f2f56c6fec8.txt @@ -0,0 +1,6 @@ +--- +source: "Engine::ActionView::TurboFrameTagTest#test_0010_turbo_frame_tag with a string prefix and a string id held in a local" +input: "{source: \"<%= turbo_frame_tag \\\"notes\\\", frame_id do %>Content<% end %>\", options: {visitors: [#], locals: {frame_id: \"post_1\"}}}" +--- +_buf = ::String.new; _buf << 'Content'.freeze; +_buf.to_s diff --git a/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0011_turbo_frame_tag_with_literal_ids_joins_them_13d15ed6e517443019e4bac66bf642f0.txt b/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0011_turbo_frame_tag_with_literal_ids_joins_them_13d15ed6e517443019e4bac66bf642f0.txt new file mode 100644 index 000000000..a7f299001 --- /dev/null +++ b/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0011_turbo_frame_tag_with_literal_ids_joins_them_13d15ed6e517443019e4bac66bf642f0.txt @@ -0,0 +1,5 @@ +--- +source: "Engine::ActionView::TurboFrameTagTest#test_0011_turbo_frame_tag with literal ids joins them" +input: "{source: \"<%= turbo_frame_tag \\\"notes\\\", :list %>\", options: {visitors: [#]}}" +--- +''.freeze \ No newline at end of file diff --git a/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0011_turbo_frame_tag_with_literal_ids_joins_them_c05c5d47b392973f974757e1d15aa2ab.txt b/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0011_turbo_frame_tag_with_literal_ids_joins_them_c05c5d47b392973f974757e1d15aa2ab.txt new file mode 100644 index 000000000..a822dba23 --- /dev/null +++ b/test/snapshots/engine/action_view/turbo_frame_tag_test/test_0011_turbo_frame_tag_with_literal_ids_joins_them_c05c5d47b392973f974757e1d15aa2ab.txt @@ -0,0 +1,5 @@ +--- +source: "Engine::ActionView::TurboFrameTagTest#test_0011_turbo_frame_tag with literal ids joins them" +input: "{source: \"<%= turbo_frame_tag \\\"notes\\\", :list %>\", locals: {}, options: {action_view_helpers: true}}" +--- + \ No newline at end of file