Sort a table of records in Rails with Ransack

Suppose you’ve got a model and you want present a list of these models to the view in such a way that the user can order, and reverse order, the list of models by any single model attribute.

Achieving this goal is easy with the gem Ransack, from Ernie Miller.  Ransack does much more than sorting, but I’m only going to cover one little feature using an example.

Start with the model

class Note < ActiveRecord::Base
 attr_accessible :title, :content
end

The generated Note controller’s index action (used to display the list of Notes) will contain code that looks something like this:

@notes = Note.all

And the generated view index.html.erb might look something like this, after a bit of refactoring:

<% unless @notes.empty? %>
 <table>
  <%= render @notes %>
 </table>
<% end %>

while the corresponding Note partial _notes.html.erb might look like

<tr>
 <td>
  <b><%= note.title %></b>,
  posted <%= time_ago_in_words(note.created_at) %> ago
 </td>
</tr>
<tr>
 <td><%= note.content %></td>
</tr>

This is just a plain old table of Notes.

Add in some Ransack magic to give the user the ability to order this list by title or content, ascending and descending. First add ransack to your Gemfile (not covered here).

The main use Ransack is to provide easy form searches, using search_form_for in the view to generate a search form. But we can get the ordering without using Ransack’s search form capability. Make the following change to the controller:

@search = Note.search(params[:q])
@notes = @search.result(:distinct => true)

The search method and the object it returns are provided by Ransack. search would normally take parameters from the search_form_for, but we”re not using that in the view. It will also take in parameters from sort_link, which we’ll use in the view to provided the ordering capability. Edit the view to read:

<% unless @notes.empty? %>
 <p>Sort by <%= sort_link @search, :title %> | <%= sort_link @search, :content %></p>
 <table>
  <%= render @notes %>
 </table>
<% end %>

That will give the user two links, the first will sort by title, the second will sort by the content.

If you’d like to provide a default sort order (created_at, descending, for example) that gets applied when the page first loads, modify the controller to read:

@search = Note.search(params[:q])
if params[:q].nil?
 @notes = @search.result(:distinct => true).order('created_at DESC')
else
 @notes = @search.result(:distinct => true)
end

Hope you find this helpful!

3 thoughts on “Sort a table of records in Rails with Ransack

  1. Hi, anyone know how to use ransack sort with select_options ?
    For example to get options_for_select with created_at+asc and options_for_select with created_at+desc
    ?

Leave a comment