Rails 7.1 gives templates more control over the locals they receive

railsSeptember 13, 2023Dotby Alkesh Ghorpade

Rails developers can break down their code into smaller, reusable partials when building complex web pages. These partials can then be passed locals, which are parameters or variables the partial needs to access.

By default, templates will accept any locals passed to them as keyword arguments. This meant templates had no control over the list of locals passed to them.

Before Rails 7.1

Before Rails 7.1, there was no in-built method to define locals explicitly or restrict the locals passed to the templates.

local_assigns is a Rails view helper method that you can use to check whether the partial has been provided with local variables or not. It returns a hash of locals passed to the partials, as shown below:

<%= render partial: "payment_gateways", locals: { paypal: @paypal, braintree: @braintree }

> local_assigns
=> { paypal: @paypal, braintree: @braintree }

> local_assigns[:paypal]
=> #<PaymentGateway id: 1, name: "Paypal"...

> local_assigns.has_key?(:stripe)
=> false

You can write a custom helper method to check if the locals passed to your templates are valid.

# app/views/shared/_payment_gateways.html.erb

<% verify_locals(local_assigns, [:paypal, :braintree]) %>

# code for the rest of the file

You can implement the verify_locals method in ApplicationHelper and add your custom logic to restrict particular locals or verify if unnecessary locals get passed to the template.

# app/helpers/application_helper.rb

def verify_locals(local_assigns, expected_locals)
  if (local_assigns.keys - expected_locals).any?
    # raise error
  end
end

Also, to set a default value in the template file, you must use the || operator.

<% name = (local_assigns[:name] || "Guest User")  %>

In Rails 7.1

In Rails 7.1, developers can define or restrict local variables a template can accept. To implement this, you must add a local magic comment inside the template.

# app/views/shared/_payment_gateways.html.erb

<%# locals: (paypal:, braintree:) -%>

Rendering a partial with local variables still works the same way, but if you pass any local variables that are not expected, Rails will raise an ActionView::Template::Error.

# app/views/orders/create.html.erb

<%= render partial: "payment_gateways", locals: { paypal: @paypal, braintree: @braintree }

# Raises error if additional or invalid locals are passed
# app/views/orders/create.html.erb

<%= render partial: "payment_gateways", locals: { paypal: @paypal, braintree: @braintree, stripe: @stripe }

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

app/views/orders/create.html.erb:10

Setting default locals

The feature will also raise an error if the expected locals are not passed.

<%= render partial: "payment_gateways", locals: { paypal: @paypal }

ActionView::Template::Error (missing local: :braintree):

app/views/orders/create.html.erb:10

You can avoid the missing local: error by setting the default values for the locals in the magic comment.

# app/views/shared/_payment_gateways.html.erb

<%# locals: (paypal: PaymentGateway.find_by_name("paypal"), braintree:...) -%>

Partials with no locals

You might need to render a partial without any locals in a few cases. To ensure the partial does not accept any locals, you need to set the local magic comment below.

# app/views/shared/_payment_gateways.html.erb

<%# locals: () -%>

If you try to pass any local to this partial, it would throw no locals accepted error.

<%= render partial: "payment_gateways", locals: { paypal: @paypal }

ActionView::Template::Error (no locals accepted):10

This feature will unlock the ability to pre-compile templates at application boot time instead of at runtime in the future.

To know more about this feature, please refer to this PR.

Closing Remark

Could your team use some help with topics like this and others covered by ShakaCode's blog and open source? We specialize in optimizing Rails applications, especially those with advanced JavaScript frontends, like React. We can also help you optimize your CI processes with lower costs and faster, more reliable tests. Scraping web data and lowering infrastructure costs are two other areas of specialization. Feel free to reach out to ShakaCode's CEO, Justin Gordon, at justin@shakacode.com or schedule an appointment to discuss how ShakaCode can help your project!
Are you looking for a software development partner who can
develop modern, high-performance web apps and sites?
See what we've doneArrow right