Unlocking Rails cycle: A Hidden Gem for Views.
When you’re working with Rails views, it’s easy to fall into habits: loops for collections, conditionals for styles, partials for structure. But tucked away in ActionView is a little helper that often gets overlooked — cycle
.
If you’ve ever written if index.even? ... else ... end
just to style alternating rows, there’s a cleaner way. And once you start using it, you’ll find plenty of creative uses.
Understanding cycle: What Does It Do?
At its core, cycle
rotates through a list of values each time it’s called. Think of it as a round-robin generator for your views.
A classic example looks like this:
<tr class="<%= cycle("odd", "even") %>">
<td>Item content</td>
</tr>
The first row gets odd
, the next even
, and so on. By the time you render a table, your rows are nicely styled without any manual index checks.
Common Use Cases in Rails Views
Alternating Row Colors in Tables
The “hello world” of cycle. In admin dashboards, reports, or any tabular data, you can keep things readable without cluttering your view logic.
<% @users.each do |user| %>
<tr class="<%= cycle("bg-white", "bg-gray-50") %>">
<td><%= user.name %></td>
<td><%= user.email %></td>
</tr>
<% end %>
Looping Through a Set of Values
You’re not limited to two options. Pass in as many values as you like:
<%= cycle("red", "green", "blue") %>
Reusing Limited Data for Layout Testing
This is where cycle shines for frontend development 😍. When testing layouts, you don’t always have a large dataset handy. Instead of creating fake records, you can cycle
a small collection to simulate more items:
<% 20.times do %>
<div class="item">
<%= cycle(*@products.map(&:name)) %>
</div>
<% end %>
Now you can see how your design holds up with overflowing content, without seeding extra data.
A Note on Modern CSS
It’s worth mentioning that some of the classic uses of cycle can now be solved directly in CSS.
For example, alternating row colors doesn’t require Rails logic anymore:
tr:nth-child(even) {
background: #f9fafb;
}
You can also style an element when it's an odd
or even
child using the odd and even variants on tailwindcss:
<table>
<!-- ... -->
<tbody>
{#each people as person}
<tr class="odd:bg-white even:bg-gray-50 dark:odd:bg-gray-900/50 dark:even:bg-gray-950">
<td>{person.name}</td>
<td>{person.title}</td>
<td>{person.email}</td>
</tr>
{/each}
</tbody>
</table>
Think of CSS and cycle as complementary tools — each with its sweet spot.
Going Beyond the Basics: More Creative Uses
Cycling Through Classes for UI Components
Need to highlight sections differently? Use cycle to rotate through predefined classes:
<section class="p-4 <%= cycle("bg-yellow-100", "bg-green-100", "bg-blue-100") %>">
<%= content %>
</section>
Step Indicators or Timelines
If you’re building a progress tracker, cycle can handle repetitive markers:
<% 5.times do %>
<div class="step">
<span class="number"><%= cycle(1, 2, 3, 4, 5) %></span>
<span class="arrow"><%= cycle('→', '⇒') %></span>
</div>
<% end %>
Nested Collections
Even in nested loops, cycle
can bring order. For example, rotating through categories while displaying posts:
<% @categories.each do |category| %>
<h2><%= category.name %></h2>
<% category.posts.each do |post| %>
<div class="post <%= cycle("a", "b", "c", name: "post_cycle") %>">
<%= post.title %>
</div>
<% end %>
<% end %>
Notice the name: option
— it lets you keep different cycles independent from each other, which is especially handy in complex views.
Potential Pitfalls and Considerations
Like any helper, cycle
isn’t always the right tool:
- Complex conditions: If your logic depends on business rules (not just alternating), an explicit conditional might be clearer.
- Multiple loops: Remember to use the
name: option
if you’re calling cycle inside different loops. Otherwise, they’ll step on each other and cause confusing results. - Debugging: Overusing
cycle
can make it harder to reason about why a particular element has a class — especially when mixing multiple cycles in a view.
Conclusion: Why cycle is a Hidden Gem
Rails has a knack for giving us small helpers that solve specific, recurring problems. cycle
is one of those.
From alternating rows to UI patterns and even layout testing, it’s more versatile than it first appears. The next time you find yourself writing conditional view logic for repeating styles or testing layouts with too little data — reach for cycle
.
It’s a small gem, but one that can keep your views both cleaner and smarter. Give it a try in your Rails app and see where it simplifies your templates.