Simple Mode
Ransack can be used in one of two modes, simple or advanced. For searching/filtering not requiring complex boolean logic, Ransack's simple mode should meet your needs.
In your controller
def index
@q = Person.ransack(params[:q])
@people = @q.result(distinct: true)
end
or without distinct: true
, for sorting on an associated table's columns (in
this example, with preloading each Person's Articles and pagination):
def index
@q = Person.ransack(params[:q])
@people = @q.result.includes(:articles).page(params[:page])
end
By default, searching and sorting are authorized on any column of your model. See Authorization (allowlisting/denylisting) on how to prevent this.
Default search options
Search parameter
Ransack uses a default :q
param key for search params. This may be changed by
setting the search_key
option in a Ransack initializer file (typically
config/initializers/ransack.rb
):
Ransack.configure do |c|
# Change default search parameter key name.
# Default key name is :q
c.search_key = :query
end
String search
After version 2.4.0 when searching a string query Ransack by default strips all whitespace around the query string.
This may be disabled by setting the strip_whitespace
option in a Ransack initializer file:
Ransack.configure do |c|
# Change whitespace stripping behavior.
# Default is true
c.strip_whitespace = false
end
In your view
The two primary Ransack view helpers are search_form_for
and sort_link
,
which are defined in
Ransack::Helpers::FormHelper.
Form helper
Ransack's search_form_for
helper replaces form_for
for creating the view search form
<%= search_form_for @q do |f| %>
# Search if the name field contains...
<%= f.label :name_cont %>
<%= f.search_field :name_cont %>
# Search if an associated articles.title starts with...
<%= f.label :articles_title_start %>
<%= f.search_field :articles_title_start %>
# Attributes may be chained. Search multiple attributes for one value...
<%= f.label :name_or_description_or_email_or_articles_title_cont %>
<%= f.search_field :name_or_description_or_email_or_articles_title_cont %>
<%= f.submit %>
<% end %>
The argument of f.search_field
has to be in this form:
attribute_name[_or_attribute_name]..._predicate
where [_or_another_attribute_name]...
means any repetition of _or_
plus the name of the attribute.
cont
(contains) and start
(starts with) are just two of the available
search predicates.
The search_form_for
answer format can be set like this:
<%= search_form_for(@q, format: :pdf) do |f| %>
<%= search_form_for(@q, format: :json) do |f| %>
Search link helper
Ransack's sort_link
helper creates table headers that are sortable links
<%= sort_link(@q, :name) %>
Additional options can be passed after the column parameter, like a different column title or a default sort order.
If the first option after the column parameter is a String, it's considered a custom label for the link:
<%= sort_link(@q, :name, 'Last Name', default_order: :desc) %>
You can use a block if the link markup is hard to fit into the label parameter:
<%= sort_link(@q, :name) do %>
<strong>Player Name</strong>
<% end %>
With a polymorphic association, you may need to specify the name of the link
explicitly to avoid an uninitialized constant Model::Xxxable
error (see issue
#421):
<%= sort_link(@q, :xxxable_of_Ymodel_type_some_attribute, 'Attribute Name') %>
If the first option after the column parameter and/or the label parameter is an Array, it will be used for sorting on multiple fields:
<%= sort_link(@q, :last_name, [:last_name, 'first_name asc'], 'Last Name') %>
In the example above, clicking the link will sort by last_name
and then
first_name
. Specifying the sort direction on a field in the array tells
Ransack to always sort that particular field in the specified direction.
Multiple default_order
fields may also be specified with a trailing options
Hash:
<%= sort_link(@q, :last_name, %i(last_name first_name),
default_order: { last_name: 'asc', first_name: 'desc' }) %>
This example toggles the sort directions of both fields, by default
initially sorting the last_name
field by ascending order, and the
first_name
field by descending order.
In the case that you wish to sort by some complex value, such as the result of a SQL function, you may do so using scopes. In your model, define scopes whose names line up with the name of the virtual field you wish to sort by, as so:
class Person < ActiveRecord::Base
scope :sort_by_reverse_name_asc, lambda { order("REVERSE(name) ASC") }
scope :sort_by_reverse_name_desc, lambda { order("REVERSE(name) DESC") }
...
and you can then sort by this virtual field:
<%= sort_link(@q, :reverse_name) %>
The trailing options Hash can also be used for passing additional options to the
generated link, like class:
.
The sort link order indicator arrows may be globally customized by setting a
custom_arrows
option in an initializer file like
config/initializers/ransack.rb
.
You can also enable a default_arrow
which is displayed on all sortable fields
which are not currently used in the sorting. This is disabled by default so
nothing will be displayed:
Ransack.configure do |c|
c.custom_arrows = {
up_arrow: '<i class="custom-up-arrow-icon"></i>',
down_arrow: 'U+02193',
default_arrow: '<i class="default-arrow-icon"></i>'
}
end
All sort links may be displayed without the order indicator
arrows by setting hide_sort_order_indicators
to true in the initializer file.
Note that this hides the arrows even if they were customized:
Ransack.configure do |c|
c.hide_sort_order_indicators = true
end
Without setting it globally, individual sort links may be displayed without
the order indicator arrow by passing hide_indicator: true
in the sort link:
<%= sort_link(@q, :name, hide_indicator: true) %>
sort_url
Ransack's sort_url
helper is like a sort_link
but returns only the url
sort_url
has the same API as sort_link
:
<%= sort_url(@q, :name, default_order: :desc) %>
<%= sort_url(@q, :last_name, [:last_name, 'first_name asc']) %>
<%= sort_url(@q, :last_name, %i(last_name first_name),
default_order: { last_name: 'asc', first_name: 'desc' }) %>
PostgreSQL's sort option
The NULLS FIRST
and NULLS LAST
options can be used to determine whether nulls appear before or after non-null values in the sort ordering.
You may want to configure it like this:
Ransack.configure do |c|
c.postgres_fields_sort_option = :nulls_first # or :nulls_last
end
To treat nulls as having the lowest or highest value respectively. To force nulls to always be first or last, use
Ransack.configure do |c|
c.postgres_fields_sort_option = :nulls_always_first # or :nulls_always_last
end
See this feature: https://www.postgresql.org/docs/13/queries-order.html
Case Insensitive Sorting in PostgreSQL
In order to request PostgreSQL to do a case insensitive sort for all string columns of a model at once, Ransack can be extended by using this approach:
module RansackObject
def self.included(base)
base.columns.each do |column|
if column.type == :string
base.ransacker column.name.to_sym, type: :string do
Arel.sql("lower(#{base.table_name}.#{column.name})")
end
end
end
end
end
class UserWithManyAttributes < ActiveRecord::Base
include RansackObject
end
If this approach is taken, it is advisable to add a functional index.
This was originally asked in a Ransack issue and a solution was found on Stack Overflow.