61 lines
2.5 KiB
Markdown
61 lines
2.5 KiB
Markdown
|
---
|
||
|
title: "Rails: Group results by week (using group_by)"
|
||
|
kind: article
|
||
|
slug: rails-group-results-by-week-using-group_by
|
||
|
created_at: 2007-01-12
|
||
|
tags:
|
||
|
- General
|
||
|
- Everything
|
||
|
- RubyOnRails
|
||
|
- Features
|
||
|
---
|
||
|
|
||
|
The Enumerable class in Rails contains a method named 'group_by'. This method is pure magic for a developer's point of view. I'll give you a simple example that shows the power of group_by.
|
||
|
|
||
|
Let's say you have a table 'posts' containing blog posts. Now, you normally show these chronologically a few at a time. Nothing special there. For some special overview page, you want to group your posts by week.
|
||
|
|
||
|
With normal ActiveRecord operations this would be quite an elaborate task. But with group_by from Enumerable, it becomes child's play.
|
||
|
<!--more-->
|
||
|
|
||
|
First of all, in the controller, just get all the posts you need. In this case, all of them:
|
||
|
|
||
|
Controller:
|
||
|
<pre lang="ruby">def list
|
||
|
@posts = Post.find :all
|
||
|
end</pre>
|
||
|
|
||
|
As you can see, I perform no ordering or whatsoever here.
|
||
|
|
||
|
Now, in your view you normally would iterate over all posts like this:
|
||
|
|
||
|
<pre lang="html">< %= render :partial => 'post', :collection => @posts %></pre>
|
||
|
|
||
|
But, as I said, we want to group the posts by week. To make life easy, I add a method to the Post class that returns the week number in which a post was written:
|
||
|
|
||
|
Model Post:
|
||
|
<pre lang="ruby">def week
|
||
|
self.created_at.strftime('%W')
|
||
|
end</pre>
|
||
|
|
||
|
Now, the magic will happen in our view:
|
||
|
|
||
|
<pre lang="html">< % @posts.group_by(&:week).each do |week, posts| %>
|
||
|
<div id="week">
|
||
|
<h2>Week < %= week %></h2>
|
||
|
< %= render :partial => 'post', :collection => @posts %>
|
||
|
</div>
|
||
|
< % end %></pre>
|
||
|
|
||
|
Let me explain the above. We specify that we want to call group_by for @posts. But we need to say how we want to group these posts. By specifying &:week we tell group_by that we want to group by the result of the week attribute of every post. This is the attribute we specified earlier in the model.
|
||
|
|
||
|
Well, when the grouping is done we create a block that will handle every group of items. We extract 'week' and 'posts' here. 'week' contains the week number and 'posts' all the posts for that week.
|
||
|
|
||
|
As normal, we can now show the week number and iterate over the posts.
|
||
|
|
||
|
<h2>Sorting groups</h2>
|
||
|
|
||
|
The result of group_by is not guaranteed to be ordered in any way. Simply call 'sort' before each and you're set:
|
||
|
|
||
|
<pre lang="ruby">@posts.group_by(&:week).sort.each do |week, posts|</pre>
|
||
|
|
||
|
Mostly, you'll find that the posts for every group are not sorted either. With the example above I think it's easy to figure out how to do that now. (hint: .sort)
|