Grouped Links in a Rails application
Background – grouped links
Normally, when people talk about paging in a web application, they mean providing next/previous links and direct links to particular page numbers. Here’s some examples you should be familiar with:



This style of paging is supported very well by the will_paginate plugin. However, some types of information don’t readily lend themselves to this type of paging. When listing people, for instance, it’s natural to want to jump directly to the ‘M’ names, just like you would with a telephone directory. For this type of information, what you want is a set of links that take you directly to the page with the first occurrence of a particular letter:

The greyed letters indicate that there are no entries beginning with that letter.
I’ve needed this for a recent project and implemented it as a patch to will_paginate, it’s available at http://github.com/dhennessy/will_paginate/tree/master for anyone who feels like trying it out.
Adding grouped links to an existing project
The grouped links plugin depends on you having a grouping attribute on the data you want to display. For the example above, this might be the first letter of the name; for a recipe application, it might be the primary ingredient. The point is that this has to exist in the database as a separate column. One easy way to maintain this is to add a before_save filter to your model that computes the grouping attribute:
before_save :update_group_letter
def update_group_letter
self.first_letter = name[0,1]
end
In your controller, you create a list of results as follows:
@people = Person.paginate :page => params[:page], :group_by => 'first_letter', :order => 'name ASC'
@people.add_missing_links(('A'..'Z').to_a)
Normally, the paginate method will add a grouped link for every distinct value of the group_by attribute. The add_missing_links method in this example will add additional links for letters that don’t already exist (which looks better in this case).
Finally, add the following to your view:
<%= will_paginate @people, :draw_if_single => true, :next_previous_links => false %>
The draw_if_single option forces the links to be displayed, even if the results all fit on a single page. Note that the resulting links will have #A, #B, etc appended to them so that you can jump to a particular row (providing you set the anchor when the first letter changes in your list). As you can see, this is very similar to the way you’re already using the will_paginate plugin.
Health Warning: this plugin should probably be treated as experimental as I may change things a bit as I get feedback from real users.