Custom Filters Using Ransacker in ActiveAdmin Interfaces
Oh, so, you have tried implementing custom filters in your shiny ActiveAdmin interface, and probably, have already started despising the time you have wasted in searching for an answer? Yeah, it happened to me, as well.
Anyways, this post contains my short notes on using ransacker
to create
powerful search patterns in my ActiveAdmin interfaces.
Definitely, ransacker
is really powerful. You only need to convert the
incoming search filter (e.g. text or ids or anything else) to an equivalent
attribute in the database, and you are done :)
Lets, imagine that we have an ActiveAdmin dashboard, with
a User
resource. Our app distinguishes users based on some mysterious logic
as: Active Users
, Inactive Users
, and New Users
. Perfect. But, now,
somehow, I need to filter my users as per this categorization (within AA). And,
this is where normal filtering methods stop working for me. Imagine that the
code present in the User
model is somewhere along these lines:
1 2 3 4 5 6 7 8 9 |
|
Step 1: Define the search filter and inputs.
In order to filter our users based on the above categorization, we first need to define our filter in AA. This is fairly easy:
1 2 |
|
Yeah, that’s it :)
But, the filter will not work, as of now, and if you try to visit your users
resource, it will spit out an error that says (something like):
1
|
|
Obviously, we are yet to define how the filtering will take place.
Step 2: Define the filtering method, a.k.a. ransacker
Alright, so the error says that the given filtering method could not be found,
and therefore, we will start with its implementation. Ransack is the
search library used by AA, and it provides a ransacker
method that we can use
in our models to define custom search methods. Since, we defined our filter as
by_categorization_in
, our ransacker method should be named as: by_categorization
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Step 3: Define our filtering algorithm
So, finally, we define how the filter will actually work. This is fairly easy
step, as well. Notice the proc
in the ransacker
method above? Also, the
parent
variable? Yeah, we need to use them to define which users will be
filtered and which will be displayed.
In the given proc
, the variable v
is nothing special, and simply, contains
the search term we are filtering upon. In our case, this will be one of the
New
, Active
or Inactive
words. The purpose of the proc
being to map this
variable to an equivalent attribute in the user’s table. Therefore, we can do
something like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
I know that the above way to find out which user ids belong to a particular
category is really inefficient, but this is an example. Alright, so we made the
proc
return some user IDs belonging to the category we were interested in.
Next is the parent
variable, which probably is some weird ruby object, and to
be honest I am not entirely sure what all capabilities it provides (though, it
seems that I can use associations, fetch records for the given model, etc. using
this object). But, what we are really interested is in the parent.table
variable, which is an instance of the Arel::Table
class, representing our
users
table in the database. The purpose of this block is to obtain an
attribute from this table (a.k.a., an Arel::Attributes::Attribute
), and match
the values returned by the proc
above with the values for this attribute
across the whole users
table. Values returned from the proc
matching the
given attribute for any record in the database table (i.e. our users
table)
will be returned and the rest entries/users will be filtered.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Done! The above should provide us with everything that we need to filter out our users based on their categorization. Happy ransacking :)