Rails 7.1.2 now ignores implicitly passed locals in templates that use strict local definitions

Templates have always been a powerful way to organize and reuse view elements. Rails 7.1 introduced strict local definitions in templates. This means that templates can now define a strict list of locals that they accept. This is useful for catching typos and other errors.

For example, to render a profile card with strict locals, a template might look like this:

# app/views/_profile.html.erb

<%# locals: (name:, avatar:) -%>

<div>
  <%= image_tag avatar %>
  <%= name %>
</div>

The magic comment locals: (name:, avatar:) defines the locals that this template accepts. If a local that is not defined is passed to this template, an exception will be raised.

# app/views/homepage/index.html.erb

<%= render partial: 'profile', locals: { name: user.name, avatar: user.avatar, address: user.address } %>

Since address is not defined in the template, this will raise an exception.

ActionView::Template::Error (unknown local: :address):

app/views/homepage/index.html.erb:2

Before

Templates can also be used to render collections. For example, to render a list of users, a template might look like this:

# app/views/users/index.html.erb
<h1>Users</h1>

<div id="users">
  <%= render @users %>
</div>

The user template might have a strict local definition like this:

# app/views/users/_user.html.erb
<%# locals: (user:) -%>

<div>
  <%= image_tag user.avatar %>
  <%= user.name %>
</div>

Technically, this should work. However, when rendering collections, Rails implicitly passes a two locals called user_counter and user_iteration to the template. This is intended behavior and well documented.

However, since the strict local definition prevents additional locals from being accepted, the template will raise an exception because it does not accept the implicitly passed local.

ActionView::Template::Error (unknown keywords: :user_counter, :user_iteration):

After

After this PR Rails now ignores implicitly passed locals in templates that use strict local definitions.

If the template has only the user local defined, then Rails will no longer implicitly pass user_counter and user_iteration to the template. This means that the above example will now work as expected.

Need help on your Ruby on Rails or React project?

Join Our Newsletter