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!
I prefer to use the sorts to order the list, such as:
@search = Note.search(params[:q])
@search.sorts ||= ''created_at.desc"
@notes = @search.result(:distinct => true)
Thanks for that! I was not even aware of
Ransack::Search#sorts=
.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
?