Skip to content

Commit 619c3a9

Browse files
committed
Clarify the use case for Strict Locals
Make it clear that it is to solve the problem of megamorphic partials and that it's not suggested to be used as a default and on all partials.
1 parent b050366 commit 619c3a9

File tree

1 file changed

+39
-14
lines changed

1 file changed

+39
-14
lines changed

guides/source/action_view_overview.md

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -599,22 +599,48 @@ enables compact partial-local default variable assignments:
599599
<% end %>
600600
```
601601

602-
INFO: By default, partials will accept any `locals` as keyword arguments. To
603-
define what `locals` a partial accepts, use a `locals:` magic comment. To learn
604-
more, read about [Strict Locals](#strict-locals).
605-
606602
[local_assigns]:
607603
https://api.rubyonrails.org/classes/ActionView/Template.html#method-i-local_assigns
608604

609605
### Strict Locals
610606

611-
Action View partials will accept any number of `locals` as keyword arguments.
607+
Action View partials are compiled into regular Ruby methods under the hood.
608+
Because it is impossible in Ruby to dynamically create local variables, every single combination of `locals` passed to
609+
a partial requires compiling another version:
610+
611+
```html+erb
612+
<%# app/views/articles/show.html.erb %>
613+
<%= render partial: "article", layout: "box", locals: { article: @article } %>
614+
<%= render partial: "article", layout: "box", locals: { article: @article, theme: "dark" } %>
615+
```
616+
617+
The above snippet will cause the partial to be compiled twice, taking more time and using more memory.
618+
619+
```ruby
620+
def _render_template_2323231_article_show(buffer, local_assigns, article:)
621+
# ...
622+
end
623+
624+
def _render_template_3243454_article_show(buffer, local_assigns, article:, theme:)
625+
# ...
626+
end
627+
```
628+
629+
When the number of combinations is small, it's not really a problem, but if it's large it can waste
630+
a sizeable amount of memory and take a long time to compile. To counter act this you can use
631+
strict locals to define the compiled partial signature, and ensure only a single version of the partial is compiled:
632+
633+
```html+erb
634+
<%# locals: (article:, theme: "light") -%>
635+
...
636+
```
637+
612638
You can enforce how many and which `locals` a template accepts, set default
613-
values, and more with a `locals:` magic comment.
639+
values, and more with a `locals:` signature, using the same syntax as Ruby method signatures.
614640

615-
Here are some examples of the `locals:` magic comment:
641+
Here are some examples of the `locals:` signature:
616642

617-
```erb
643+
```html+erb
618644
<%# app/views/messages/_message.html.erb %>
619645
620646
<%# locals: (message:) -%>
@@ -640,15 +666,14 @@ If a default value is set then it can be used if `message` is not passed in
640666
```
641667

642668
Rendering the partial without a `:message` local variable uses the default value
643-
set in the `locals:` magic comment:
669+
set in the `locals:` signature:
644670

645671
```ruby
646672
render "messages/message"
647673
# => "Hello, world!"
648674
```
649675

650-
Rendering the partial with local variables not specified in the `local:` magic
651-
comment will also raise an exception:
676+
Rendering the partial with local variables not specified in the `local:` signature will also raise an exception:
652677

653678
```ruby
654679
render "messages/message", unknown_local: "will raise"
@@ -682,15 +707,15 @@ render "messages/message", unknown_local: "will raise"
682707
# => ActionView::Template::Error: no locals accepted for app/views/messages/_message.html.erb
683708
```
684709

685-
Action View will process the `locals:` magic comment in any templating engine
686-
that supports `#`-prefixed comments, and will read the magic comment from any
710+
Action View will process the `locals:` signature in any templating engine
711+
that supports `#`-prefixed comments, and will read the signature from any
687712
line in the partial.
688713

689714
CAUTION: Only keyword arguments are supported. Defining positional or block
690715
arguments will raise an Action View Error at render-time.
691716

692717
The `local_assigns` method does not contain default values specified in the
693-
`local:` magic comment. To access a local variable with a default value that
718+
`local:` signature. To access a local variable with a default value that
694719
is named the same as a reserved Ruby keyword, like `class` or `if`, the values
695720
can be accessed through `binding.local_variable_get`:
696721

0 commit comments

Comments
 (0)