Oct 13, 2008 @ 03:44 pm

Flashback time. We are in 1999 and you are coding in ASP thinking that this language is the future. You use ADODB recordsets to iterate over collections. You have a recordset containing some records from a “quotes” table. The “quotes” table contains a author column (varchar) and a body column (varchar). Now you want to display the results grouped by author name so it looks like this :

Georges Brassens
- Les filles quand ça dit “je t’aime”, c’est comme un second baptême
- Aucune idée sur terre n’est digne d’un trépas

Billie Holiday
- Don’t threaten me with love, baby. Let’s just go walking in the rain.
- I never hurt nobody but myself and that’s nobody’s business but my own.

Assuming your recordset is ordered by author, you do something like this (remember, we’re in 1999) :

  1. <TABLE style="color:fushia;font-style:MSONormal generated=frontpage">
  2. <%while not objRS.eof %>
  3. <%if(current_author <> objRS("author"))%>
  4. <h1><%=objRS("author")%></h1>
  5. <%end if%>
  6. <Tr><td><%=objRS("body")</td></TR>
  7. <%current_author = objRS("author")%>
  8. <%objRS.MoveNext%>
  9. <%loop%>
  10. <%objRS.close%>
  11. </TABLE>

Ok welcome back in 2008. ASP is dead. You are coding in rails and you want to do the same thing. How will you do it? Storing the author name in a buffer variable like in 1999? Not too sure about it.

This is a job for Enumerable#group_by (Enumerable is a module that is mixed in the Array class)

  1. all_quotes = Quote.find(:all)
  2. @authors = all_quotes.group_by(&:author)

Enumerable#group_by will create different sets of quotes based on the “author” values. Why the “&” sign? It’s because group_by expects a block. I could have done it this way : @authors = all_quotes.group_by{|quote| quote.author}

So @authors is now a hash that will look like this:

{”George Brassens” => [#<Quote id:131 …>, #<Quote id:331 …>], “Billie Holiday” => [#<Quote id:111 …>, #<Quote id:911 …>] }

Now you can iterate over it like this :

  1. @authors.each_pair do |author_name, quotes|
  2.   <h1><%=author_name%></h1>
  3.   <%quotes.each do |quote| %>
  4.     - <%=quote.body%><br />
  5.   <%end%>
  6. <%end%>

One more thing to note : @authors is a hash, and hashes cannot be ordered. If you want to display quotes by sorted author name, you could do this :

  1. @authors.keys.sort.each do |author_name|
  2.   <h1><%=author_name%></h1>
  3.   <%@authors[author_name].each do |quote|%>
  4.     - <%=quote.body%><br />
  5.   <%end%>
  6. <%end%>

Note : Enumerable#group_by does not exist in ruby 1.8, it only exists in Rails. The method will be in ruby 1.9 however.

Bookmark this post : These icons link to social bookmarking sites where readers can share and discover new web pages.
  • DZone
  • Reddit
  • del.icio.us
  • Digg
  • Furl
  • Technorati
  • StumbleUpon
Rate this post :
1 Star2 Stars3 Stars4 Stars5 Stars (3 votes, average: 5 out of 5)
Loading ... Loading ...
Posted under : In depth
3 Comments
MyAvatars 0.2

You can also do:

@authors.sort.each do |author_name, quote|

because Hash#sort returns an array of 2-value arrays of the form [key, value]

Comment by : Grant Hutchins
— October 19, 2008 @ 3:05 am

MyAvatars 0.2

Grant, this is even better than @authors.keys.sort.each, thanks for sharing.

Comment by : Frank
— October 19, 2008 @ 9:20 am

MyAvatars 0.2

Thanks for this, very helpful for us who don’t yet know all the nooks and crannys in rails and ruby!

Comment by : Chess
— October 19, 2008 @ 11:08 pm




Leave a comment
Name (required)
Email (will not be publish) (required)
Website