views:

85

answers:

4

I have a books model with a date type column named publish_date. On my views I'm iterating through the books and I want to group the books by year such that I have a heading for every year and books that were published on that year to be listed below the year heading.

So by starting with "2010" all books published on 2010 would be listed, then another heading "2009" with all books published in 2009 listed below it and so forth.

<% @all_books.each do |book| %>
   <%=link_to book.title + ", (PDF, " + get_file_size(book.size) + ")" %>
<% end %>

By doing a book.publish_date.strftime("%Y") I am able to get the year but I do not know how to group the entries by year. Any help on this would be appreciated.

+5  A: 

You can use group_by (see API) like (of the top of my head

<% @all_books.group_by(&:year).each do |year, book| %>

   ...
<% end %>
jhwist
fix: the block would receive two vars (grouping attribute and array of objects)
Eimantas
A: 
def year
  self.created_at.strftime('%Y')
end

< % @all_books.group_by(&:year).each do |year, book| %>

Year < %= year %>
# render books here

< % end %>

What say?

Webbisshh
thanks a bunch Webbisshh for your quick response and a neat solution
kibyegn
Keep in mind this is a bit of a kludge compared to what you can do with the DateTime class itself.
tadman
+2  A: 

You can use group_by for convenience, but your need can be better served by relying on DB for sorting and a each loop. This avoids the cost of client side sorting and hash manipulations for grouping.

Somewhere in your controller

@all_books = Book.all(:order => "publish_date DESC")

In your view

<%year = nil
  @all_books.each do |book| 
    if year.nil? or year > book.publish_date.year 
      year = book.publish_date.year 
%>
      <h1> <%=year%><h1>
  <%end % >
  <%=link_to book.title + ", (PDF, " + get_file_size(book.size) + ")" %>
<%end %>
KandadaBoggu
Thanks KandadaBoggu for your solution, works like a charm
kibyegn
A: 

The quick and dirty approach is to simply group_by the year and iterate over those:

@all_books.group_by { |b| b.created_at.year }.each do |year, books|
  # All books for one year, so put heading here
  books.each do |book|
    # ...
  end
end

This requires sorting within the Rails application, so you will need to retrieve all relevant records in order to have the data properly organized. To do the sort on the server you will probably need to introduce a year column and keep it in sync with the created_at time.

tadman