ActiveAdmin Filters—Unlocking the Power of Ransack
Ryan Stenberg, Former Developer
Article Category:
Posted on
For those who aren't familiar with ActiveAdmin, it provides a nice out-of-the-box admin interface for Rails projects that has a pretty solid DSL. If you've never heard of ActiveAdmin or used it before -- check out the documentation!
ActiveAdmin has some pretty great out-of-the-box filters on resource index pages, which lets you search on a field-by-field basis to scope the collection of records. On each index page, any field you have on a given model will get a corresponding filter based on the underlying column's data type or whether or not it represents an association.
ActiveAdmin takes care of the DSL for defining filters as well as how they look on a page, but all the heavy lifting is done behind the scenes with the Ransack gem. If we want to do sweet, sweet things with filters, one must first learn how to harness the power of Ransack.
Understanding Ransack
Ransack provides a string-based query interface that allows you to search against a given model in a number of ways. To illustrate, let's say we had a User
model and we wanted to find all the Users who had emails ending in 'gmail.com'. Using Ransack, here's what that search would look like:
User.search(email_end: 'gmail.com').result
The _end
is what Ransack refers to as a predicate. The predicate defines how to search. There are a number of available predicates that you can use to construct Ransack queries.
Ransack also supports searching across multiple fields/columns using or
. Continuing with our User
example, let's say we want to find Users who have a first name or last name that contain 'bob'. Here's the Ransack query:
User.search(first_name_or_last_name_cont: 'bob').result
Ransack also lets you search across associations. If our User
had a polymorphic :has_many
association to a Preference
model that has a content
field, we'd be able to search for Users having particular preference content like so:
User.search(preferences_content_cont: 'movies').result
Ransack gives you a pretty simple way to search your data and knowing how to construct your own Ransack queries gives you a lot of control over how filters function in ActiveAdmin.
Tying Ransack & ActiveAdmin Filters Together
As we just covered, Ransack is the muscle behind ActiveAdmin filters. ActiveAdmin basically gives us a nice UI on top of Ransack. By default, ActiveAdmin will let you define both the value to search for as well as picking the predicate to use.
That gives us a lot of flexibility, which is pretty great.
Knowing this, we're able to customize the filters to fit our needs. Here's a few examples to show the kinds of things you can do.
Filter Without a Predicate Dropdown
If we want our first_name
filter to always search for Users containing a given value -- and thus removing the need for a predicate dropdown, we're able to simply provide a predicate instead of a field name:
ActiveAdmin.describe User do filter :first_name_cont, label: 'First Name' end
Gives us:
Filter for Multiple Fields
Building on the previous example, if we wanted to search across first name and last name under a 'Name' filter...no problem!
ActiveAdmin.describe User do filter :first_name_or_last_name_cont, label: 'Name' end
Gives us:
Filter Across An Association
Borrowing the User preferences example from the Ransack section, we could easily turn that into a filter:
ActiveAdmin.describe User do filter :preferences_content_cont, label: 'Preferences' end
Gives us:
Multiple Associations with the Same Source Class
If our User
model had an association to other Users called favorite_friend
and favorite_family_member
and we wanted to find all Users having a given User as a favorite friend or family member, here's how we could set up a filter:
ActiveAdmin.describe User do filter :favorite_friend_id_or_favorite_family_member_id, collection: -> { User.all }, label: 'Favorite Person' end
Gives us:
Wrapping Up
Hopefully you've picked up a trick or two for the next time you need to do some filtering magic in ActiveAdmin. Whether you're filtering in ActiveAdmin or implementing search in a Rails app, learn and master Ransack for great justice!