Using Filterrific gem for filtering, searching, and sorting list of ActiveRecord objects:
* Persist filter settings in the HTTP session or DB.
* Integrates with pagination (will_paginate or kaminari).
* Reset filter to default settings.
* Relies on ActiveRecord scopes.
* Shuttles filter settings from a filter UI to the controller and ActiveRecord.
* Can be used for HTML/JSON/JS/XML response formats.
27. Model – Add filterrific Direc1ve
# student.rb
Filterrific(
default_filter_params:
{ sorted_by: 'created_at_desc' },
available_filters: [
:sorted_by,
:search_query,
:with_country_id,
:with_created_at_gte
]
)
Define default filter seOngs
Specify which scopes are available to
Filterrific.
This is a safety mechanism to prevent
unauthorized access to your database.
It’s like strong parameters, just for
filter seOngs.
Enable Filterrific for the Student class
28. Model – Define Select Op1ons
# student.rb
def self.options_for_sorted_by
[
['Name (a-z)', 'name_asc'],
['Registration date (newest first)',
'created_at_desc'],
['Registration date (oldest first)',
'created_at_asc'],
['Country (a-z)', 'country_name_asc']
]
End
# country.rb
def self.options_for_select
order('LOWER(name)').map { |e| [e.name, e.id] }
end
These class methods
provide op1ons for
select drop-down and
are called in the
controller as part of
ini1alize_filterrific.
29. Model – Define Scopes
scope :sorted_by, -> { |sort_key|
# Sort students by sort_key
direction = (sort_key =~ /desc$/) ? 'desc' : 'asc’
...
}
scope :search_query, -> { |query|
# Filters students that matches the query
...
}
scope :with_country_id, -> { |country_ids|
# Filters students with any of the given country_ids
where(:country_id => [*country_ids])
}
scope :with_created_at_gte, -> { |ref_date|
# Filter students whom registered from the given date
where('students.created_at >= ?',
Date.strptime(ref_date, "%m/%d/%Y"))
}
30. Model – Define Scopes
scope :sorted_by, -> { |sort_key|
# Sort students by sort_key
direction = (sort_key =~ /desc$/) ? 'desc' : 'asc’
...
}
scope :search_query, -> { |query|
# Filters students that matches the query
...
}
scope :with_country_id, -> { |country_ids|
# Filters students with any of the given country_ids
where(:country_id => [*country_ids])
}
scope :with_created_at_gte, -> { |ref_date|
# Filter students whom registered from the given date
where('students.created_at >= ?',
Date.strptime(ref_date, "%m/%d/%Y"))
}
Filterrific relies heavily on Ac1veRecord scopes for filtering, so it is
important that you are familiar with how to use scopes.
hCp://filterrific.clearcove.ca/pages/ac1ve_record_scope_paCerns.html
33. Controller – ini1alize_filterrific
# students_controller.rb
def index
@filterrific = initialize_filterrific(
Student,
params[:filterrific],
select_options: {
sorted_by: Student.options_for_sorted_by,
with_country_id: Country.options_for_select
}
persistence_id: 'shared_key',
default_filter_params: {},
available_filters: [],
) or return
@students = @filterrific.find.page(params[:page])
...
end
Filterrific lives in the controller’s index ac1on.
34. Controller – ini1alize_filterrific
# students_controller.rb
def index
@filterrific = initialize_filterrific(
Student,
params[:filterrific],
select_options: {
sorted_by: Student.options_for_sorted_by,
with_country_id: Country.options_for_select
}
persistence_id: 'shared_key',
default_filter_params: {},
available_filters: [],
) or return
@students = @filterrific.find.page(params[:page])
...
end
An Ac1veRecord-based model class.
It can also be an Ac1veRecord rela1on.
35. Controller – ini1alize_filterrific
# students_controller.rb
def index
@filterrific = initialize_filterrific(
Student,
params[:filterrific],
select_options: {
sorted_by: Student.options_for_sorted_by,
with_country_id: Country.options_for_select
}
persistence_id: 'shared_key',
default_filter_params: {},
available_filters: [],
) or return
@students = @filterrific.find.page(params[:page])
...
end
Any params submiCed via web request.
If they are blank, filterrific will try params
persisted in the session next.
If those are blank, too, filterrific will use the
model's default filter seOngs.
36. Controller – ini1alize_filterrific
# students_controller.rb
def index
@filterrific = initialize_filterrific(
Student,
params[:filterrific],
select_options: {
sorted_by: Student.options_for_sorted_by,
with_country_id: Country.options_for_select
}
persistence_id: 'shared_key',
default_filter_params: {},
available_filters: [],
) or return
@students = @filterrific.find.page(params[:page])
...
end
Store any op1ons for <select> inputs in the
form.
The key refers to scope name defined in the
model
The value refers to method defined in the
model that return an array of op1ons
37. Controller – ini1alize_filterrific
# students_controller.rb
def index
@filterrific = initialize_filterrific(
Student,
params[:filterrific],
select_options: {
sorted_by: Student.options_for_sorted_by,
with_country_id: Country.options_for_select
}
persistence_id: 'shared_key',
default_filter_params: {},
available_filters: [],
) or return
@students = @filterrific.find.page(params[:page])
...
end
Defaults to "<controller>#<ac1on>" string
to isolate session persistence of mul1ple
filterrific instances.
Override this to share session persisted
filter params between mul1ple filterrific
instances.
Set to false to disable session persistence.
38. Controller – ini1alize_filterrific
# students_controller.rb
def index
@filterrific = initialize_filterrific(
Student,
params[:filterrific],
select_options: {
sorted_by: Student.options_for_sorted_by,
with_country_id: Country.options_for_select
}
persistence_id: 'shared_key',
default_filter_params: {},
available_filters: [],
) or return
@students = @filterrific.find.page(params[:page])
...
end
To override model defaults
39. Controller – ini1alize_filterrific
# students_controller.rb
def index
@filterrific = initialize_filterrific(
Student,
params[:filterrific],
select_options: {
sorted_by: Student.options_for_sorted_by,
with_country_id: Country.options_for_select
}
persistence_id: 'shared_key',
default_filter_params: {},
available_filters: [],
) or return
@students = @filterrific.find.page(params[:page])
...
end
To further restrict which filters are
in this filterrific instance.
40. Controller – ini1alize_filterrific
# students_controller.rb
def index
@filterrific = initialize_filterrific(
Student,
params[:filterrific],
select_options: {
sorted_by: Student.options_for_sorted_by,
with_country_id: Country.options_for_select
}
persistence_id: 'shared_key',
default_filter_params: {},
available_filters: [],
) or return
@students = @filterrific.find.page(params[:page])
...
end
This method also persists the
params in the session and handles
reseOng the filterrific params.
41. Controller – ini1alize_filterrific
# students_controller.rb
def index
@filterrific = initialize_filterrific(
Student,
params[:filterrific],
select_options: {
sorted_by: Student.options_for_sorted_by,
with_country_id: Country.options_for_select
}
persistence_id: 'shared_key',
default_filter_params: {},
available_filters: [],
) or return
@students = @filterrific.find.page(params[:page])
...
end
In order for reset_filterrific to work, it’s
important that we add the 'or return' bit
aher the call to 'ini1alize_filterrific'.
Otherwise the redirect will not work.
42. Controller – ini1alize_filterrific
# students_controller.rb
def index
@filterrific = initialize_filterrific(
Student,
params[:filterrific],
select_options: {
sorted_by: Student.options_for_sorted_by,
with_country_id: Country.options_for_select
}
persistence_id: 'shared_key',
default_filter_params: {},
available_filters: [],
) or return
@students = @filterrific.find.page(params[:page])
...
end
This method also persists the
params in the session and handles
reseOng the filterrific params.
Returns an Ac1veRecord rela1on
for all records that match the
filter seOngs.
We can paginate with
will_paginate or kaminari.
The rela1on returned can be
chained with other scopes to
further narrow down the scope of
the list, e.g., to apply permissions
or to exclude certain types of
records.