DEV Community

matt swanson
matt swanson

Posted on • Originally published at boringrails.com on

Use Rails `cycle` to avoid `i % 2 == 0` in your view loops

Sometimes you need to keep track of how many times you’ve looped when rending some views, for instance to alternate background colors to create a “striped” table.

<!-- @foods = ["apple", "orange", "banana"] -->

<% @foods.each do |food| %>
  <tr class="???">
    <td><%= food %></td>
  </tr>
<% end %>
Enter fullscreen mode Exit fullscreen mode

You might try using :odd or :even CSS child selectors or switching to each_with_index.

<% @foods.each_with_index do |food, i| %>
  <tr class="<%= i % 2 == 0 ? 'bg-gray-200' : 'bg-gray-100' %>">
    <td><%= food %></td>
  </tr>
<% end %>
Enter fullscreen mode Exit fullscreen mode

You could even refactor a bit to use i.odd? or i.even?.

<% @foods.each_with_index do |food, i| %>
  <tr class="<%= i.even? ? 'bg-gray-200' : 'bg-gray-100' %>">
    <td><%= food %></td>
  </tr>
<% end %>
Enter fullscreen mode Exit fullscreen mode

Rails offers a different helper that comes in handy for these situations: cycle.

Usage

The cycle helper takes an array of arguments and loops through them each time it is called.

We could replace the above code with:

<% @foods.each_with_index do |food, i| %>
  <tr class="<%= cycle('bg-gray-200', 'bg-gray-100') %>">
    <td><%= food %></td>
  </tr>
<% end %>
Enter fullscreen mode Exit fullscreen mode

The real benefits start to appear if you need more than two options.

<% @foods.each_with_index do |food, i| %>
  <tr class="<%= cycle('bg-red-100', 'bg-orange-100', 'bg-yellow-100') %>">
    <td><%= food %></td>
  </tr>
<% end %>
Enter fullscreen mode Exit fullscreen mode

If you need to manually reset or share a cycle between code, you can pass a name: key as an option.

cycle("red", "white", "blue", name: "colors")
cycle("sm", "md", "lg", "xl", name: "sizes")

reset_cycle("colors")
reset_cycle("sizes")
Enter fullscreen mode Exit fullscreen mode

You can also use any object that responds to to_s in the cycle.

<% @items.each do |item| %>
  <div class="rotate-<%= cycle(0, 45, 90, 135, 180) %>">
    <%= item %>
  </div>
<% end %>
Enter fullscreen mode Exit fullscreen mode

Additional Resources

Rails API Docs: TextHelper#cycle

Tailwind Docs: Even/odd variants


Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post →

Top comments (0)

AWS Q Developer image

Your AI Code Assistant

Generate and update README files, create data-flow diagrams, and keep your project fully documented. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE