Skip to content

Commit

Permalink
Merge pull request #52205 from Shopify/local-assigns-strict-locals
Browse files Browse the repository at this point in the history
Also pass `local_assigns` to strict locals templates
  • Loading branch information
byroot committed Jun 24, 2024
1 parent 9e370f0 commit d3016bb
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 5 deletions.
7 changes: 7 additions & 0 deletions actionview/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
* Fix templates with strict locals to also include `local_assigns`

Previously templates defining strict locals wouldn't receive the `local_assigns`
hash.

*Jean Boussier*

## Rails 7.2.0.beta2 (June 04, 2024) ##

* No changes.
Expand Down
2 changes: 1 addition & 1 deletion actionview/lib/action_view/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ def _run(method, template, locals, buffer, add_to_stack: true, has_strict_locals

if has_strict_locals
begin
public_send(method, buffer, **locals, &block)
public_send(method, locals, buffer, **locals, &block)
rescue ArgumentError => argument_error
raise(
ArgumentError,
Expand Down
9 changes: 5 additions & 4 deletions actionview/lib/action_view/template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -439,9 +439,9 @@ def compiled_source
method_arguments =
if set_strict_locals
if set_strict_locals.include?("&")
"output_buffer, #{set_strict_locals}"
"local_assigns, output_buffer, #{set_strict_locals}"
else
"output_buffer, #{set_strict_locals}, &_"
"local_assigns, output_buffer, #{set_strict_locals}, &_"
end
else
"local_assigns, output_buffer, &_"
Expand Down Expand Up @@ -500,11 +500,12 @@ def compile(mod)

return unless strict_locals?

parameters = mod.instance_method(method_name).parameters - [[:req, :output_buffer]]
parameters = mod.instance_method(method_name).parameters
parameters -= [[:req, :local_assigns], [:req, :output_buffer]]

# Check compiled method parameters to ensure that only kwargs
# were provided as strict locals, preventing `locals: (foo, *foo)` etc
# and allowing `locals: (foo:)`.

non_kwarg_parameters = parameters.select do |parameter|
![:keyreq, :key, :keyrest, :nokey].include?(parameter[0])
end
Expand Down
5 changes: 5 additions & 0 deletions actionview/test/template/template_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,11 @@ def test_rails_injected_locals_can_be_specified
assert_equal "Hello", render(message: "Hello", implicit_locals: %i[message])
end

def test_rails_local_assigns_and_strict_locals
@template = new_template("<%# locals: (class: ) -%>\n<%= local_assigns[:class] %>")
assert_equal "some-class", render(class: "some-class", implicit_locals: %i[message])
end

def test_rails_injected_locals_can_be_specified_as_kwargs
@template = new_template("<%# locals: (message: 'Hello', **kwargs) -%>\n<%= kwargs[:message_counter] %>-<%= kwargs[:message_iteration] %>")
assert_equal "1-2", render(message: "Hello", message_counter: 1, message_iteration: 2, implicit_locals: %i[message_counter message_iteration])
Expand Down

0 comments on commit d3016bb

Please sign in to comment.