60 lines
2.4 KiB
Markdown
60 lines
2.4 KiB
Markdown
|
+++
|
||
|
date = "2007-01-12"
|
||
|
title = "Rails: Group results by week (using group_by)"
|
||
|
tags = ["General", "Everything", "RubyOnRails", "Features"]
|
||
|
slug = "rails-group-results-by-week-using-group_by"
|
||
|
+++
|
||
|
|
||
|
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.
|
||
|
|
||
|
First of all, in the controller, just get all the posts you need. In this case, all of them:
|
||
|
|
||
|
Controller:
|
||
|
|
||
|
def list
|
||
|
@posts = Post.find :all
|
||
|
end
|
||
|
|
||
|
As you can see, I perform no ordering or whatsoever here.
|
||
|
|
||
|
Now, in your view you normally would iterate over all posts like this:
|
||
|
|
||
|
<%= render :partial => 'post', :collection => @posts %>
|
||
|
|
||
|
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:
|
||
|
|
||
|
def week
|
||
|
self.created_at.strftime('%W')
|
||
|
end
|
||
|
|
||
|
Now, the magic will happen in our view:
|
||
|
|
||
|
<% @posts.group_by(&:week).each do |week, posts| %>
|
||
|
<div id="week">
|
||
|
<h2>Week < %= week %></h2>
|
||
|
< %= render :partial => 'post', :collection => @posts %>
|
||
|
</div>
|
||
|
<% end %>
|
||
|
|
||
|
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.
|
||
|
|
||
|
## Sorting groups
|
||
|
|
||
|
The result of group_by is not guaranteed to be ordered in any way. Simply call 'sort' before each and you're set:
|
||
|
|
||
|
@posts.group_by(&:week).sort.each do |week, posts|
|
||
|
|
||
|
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)
|
||
|
|
||
|
|