Skip to content

Linter Rule: Disallow block arguments that shadow an enclosing binding

Rule: erb-no-shadowed-block-argument

Description

Disallow a block argument or for loop index that reuses a name already bound by an enclosing block or for loop.

erb
<% @groups.each do |item| %>
  <% @items.each do |item| %>
Block argument `item` shadows an outer `item`. Rename it so both remain reachable. (erb-no-shadowed-block-argument)
<%= item %> <% end %> <% end %>
Block argument `item` shadows an outer `item`. Rename it so both remain reachable.

Rationale

Once an inner block reuses a name, the outer binding is unreachable for the rest of that block. Anything in the inner body that meant to refer to the outer value silently gets the inner one instead, and the template still renders, just with the wrong data.

It also makes a template hard to read. In a nested loop, <%= item %> gives no indication of which item is in play without tracing the nesting by eye.

The offense is reported on the inner argument, since that is the one to rename.

Examples

✅ Good

erb
<% @groups.each do |group| %>
  <% group.items.each do |item| %>
    <%= item %>
  <% end %>
<% end %>
erb
<% @groups.each do |item| %>
  <%= item %>
<% end %>

<% @items.each do |item| %>
  <%= item %>
<% end %>

🚫 Bad

erb
<% @groups.each do |item| %>
  <% @items.each do |item| %>
Block argument `item` shadows an outer `item`. Rename it so both remain reachable. (erb-no-shadowed-block-argument)
<%= item %> <% end %> <% end %>
erb
<% for item in @groups %>
  <% @items.each do |item| %>
Block argument `item` shadows an outer `item`. Rename it so both remain reachable. (erb-no-shadowed-block-argument)
<%= item %> <% end %> <% end %>
erb
<% @a.each do |item| %>
  <% @b.each do |other| %>
Block argument `other` is never used. Remove it and write `<% @b.each do %>`, or prefix it with an underscore as `_other` to show it is intentionally unused. (erb-no-unused-block-argument)
<% @c.each do |item| %>
Block argument `item` shadows an outer `item`. Rename it so both remain reachable. (erb-no-shadowed-block-argument)
<%= item %> <% end %> <% end %> <% end %>

References

Released under the MIT License.