Headers per date in Haml: How to create a Haml view that summarizes items by date
posted 2012-Feb-14
You have a Ruby web application that uses Haml—be it Rails, Sinatra, or some other framework. You have a list of timestamped items that you want to output with a separate header for each day. You want output like this:
<h2>2012-Feb-14</h2> <ul> <li><a href="/item/14">Good Stuff</a></li> <li><a href="/item/7">More Good Stuff</a></li> </ul> <h2>2012-Feb-13</h2> <ul> <li><a href="/item/2">Older Thingy</a></li> </ul>
In ERB you might do something horrible like so:
<% unless @items.empty? last_date = nil @items.sort_by(&:time).each do |item| date = item.time.strftime('%Y-%b-%d') if date != last_date if last_date then %></ul><% end %><h2><%=date%></h2><ul><% last_date = date end %><li><a href="/item/<%=item.id%>"><%=item.name%></a></li><% end %></ul><% end %>
Using Enumerable#group_by
and Haml, however, you can make something far more elegant:
- @items.sort_by(&:time).group_by{ |item| item.time.strftime('%Y-%b-%d') }.each do |day,day_items| %h2= day %ul - day_items.each do |item| %li %a{href:"/item/#{item.id}"}= item.name
Let Ruby create the sub-groups for you! You don’t even need the test for empty?
that you need in ERB, since an empty array will create an empty Hash, and it will never be iterated.