Sorting
Sorting in the View
You can add a form to capture sorting and filtering options together.
# app/views/posts/index.html.erb
<%= search_form_for @q do |f| %>
<%= f.label :title_cont %>
<%= f.search_field :title_cont %>
<%= f.submit "Search" %>
<% end %>
<table>
<thead>
<tr>
<th><%= sort_link(@q, :title, "Title") %></th>
<th><%= sort_link(@q, :category, "Category") %></th>
<th><%= sort_link(@q, :created_at, "Created at") %></th>
</tr>
</thead>
<tbody>
<% @posts.each do |post| %>
<tr>
<td><%= post.title %></td>
<td><%= post.category %></td>
<td><%= post.created_at.to_s(:long) %></td>
</tr>
<% end %>
</tbody>
</table>
Sorting in the Controller
To specify a default search sort field + order in the controller index:
# app/controllers/posts_controller.rb
class PostsController < ActionController::Base
def index
@q = Post.ransack(params[:q])
@q.sorts = 'title asc' if @q.sorts.empty?
@posts = @q.result(distinct: true)
end
end
Multiple sorts can be set by:
# app/controllers/posts_controller.rb
class PostsController < ActionController::Base
def index
@q = Post.ransack(params[:q])
@q.sorts = ['title asc', 'created_at desc'] if @q.sorts.empty?
@posts = @q.result(distinct: true)
end
end
Sorting on Association Attributes
You can sort on attributes of associated models by using the association name followed by the attribute name:
# Sort by the name of the associated category
@q = Post.ransack(s: 'category_name asc')
@posts = @q.result
# Sort by attributes of nested associations
@q = Post.ransack(s: 'category_section_title desc')
@posts = @q.result
Sorting on Globalized/Translated Attributes
When working with internationalized models (like those using the Globalize gem), special care is needed when sorting on translated attributes of associations. The simplest approach is to use the sort_link helper directly with the translation attribute:
<!-- This works perfectly for sorting on translated attributes -->
<%= sort_link @q, :translations_name %>
<%= sort_link @q, :category_translations_name %>
For programmatic sorting, let Ransack handle the joins first:
# Let Ransack establish the necessary joins for sorting
@q = Book.ransack(s: 'category_translations_name asc')
@books = @q.result.joins(:translations)
# For complex scenarios with multiple translations
@q = Book.ransack(s: 'category_translations_name asc')
@books = @q.result.includes(:translations, category: :translations)
This ensures that Ransack properly handles the join dependencies between your main model’s translations and the associated model’s translations.
Unknown sorts
A sort on an attribute that is not in ransortable_attributes, or that does
not exist, is dropped silently. Any other sorts in the same request still
apply, but the model’s default ordering does not: once a sort list is given,
Ransack replaces the default order, so a request whose only sort is invalid
comes back with no ORDER BY at all. Under a strict search (ransack!, or
ignore_unknown_conditions = false) an invalid sort raises
Ransack::InvalidSearchError instead, the same way an unknown attribute in a
condition does. A sort backed by a sort_by_<attribute>_<direction> scope is
always accepted.
Person.ransack!(s: 'secret_column asc')
# Ransack::InvalidSearchError: Invalid sort term secret_column
Before Ransack 6.0 a strict search checked only conditions, and an invalid sort was dropped silently.
Assigning sorts
sorts= replaces the current sorts, so @q.sorts = [] clears them and
assigning twice keeps only the second assignment. Use build_sort to add
one:
@q.sorts = ['title asc', 'created_at desc']
@q.build_sort(name: 'id', dir: 'asc') # title, created_at, id
@q.sorts = [] # no ORDER BY
Before Ransack 6.0 every assignment appended to the list, so sorts could only
be reset with @q.sorts.clear.