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 %>
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 %>
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 %>
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 %>
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 %>
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")
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 %>
Additional Resources
Rails API Docs: TextHelper#cycle
Tailwind Docs: Even/odd variants
Top comments (0)