Even the most ardent adherent of skinny controllers will find themselves plagued by the ferocious number of filters demanded for any non-trivial search on their models. Given enough attributes, you’ll notice your controller starting to look a little hairy
1 2 3 4 5 6 7 |
|
The horrifying trend will only continue as our demand for searching power grows, which begs the question: How can we tame this mess?
Strong Params
Your first line of defense against this will be using strong params to your advantage. They’re not only for creating objects.
Let’s try something out in the console:
1 2 3 4 5 |
|
So by using permit on our parameters object, we can filter down a hash to only our permitted values. So what if we did something like this?
1 2 3 4 5 6 |
|
With that we’ve already cleaned out a lot of the cruft of our controller, but what about that last one?
Scoping and Class Methods
We can get rid of it as well, using either scoping or class methods to take care of it for us:
1 2 3 4 5 6 7 8 9 |
|
Which will let us trim down our controller even a little more here:
1 2 3 4 5 |
|
Conditional Scoping
The astute reader will note that the above method is going to fail gloriously should we forget either of those params. We could always drop it to another variable and mutate people, but that’s generally frowned upon and doesn’t normally produce superheroes.
What we can do, however, is introduce a more conditional scoping method. Class methods are, after all, ruby methods. Let’s use them to their potential a bit more:
1 2 3 4 5 |
|
By throwing in an all
, we can conditionally chain freely.
Like Scoping
The problem is, that name search just isn’t doing it for us. We don’t want to break out solr
or trigrams
quite yet, but we can use some like
queries to make it a bit more flexible:
1 2 3 4 5 6 |
|
Though we spend all that time getting rid of postfix if
checks, can we do something about this one as well?
1 2 3 4 5 6 7 8 9 |
|
That we can:
1 2 3 4 5 6 7 8 9 |
|
Like that, we’ve eliminated another suffix if.
More advanced filtering
Though most of these examples have been fairly straightforward, there will be times when you have to break out some joins and other operations depending on your parameters. Strong params aren’t going to cut it on those, but class methods just might do the trick.
We have a new model to work with, Post
, and with it the following controller:
1 2 3 4 5 6 7 8 |
|
Some of those earlier techniques just aren’t going to cut it, and it’s going to be a lot more difficult to be intention revealing here. Including comments and tags unless we have to could be a big expense, so we need to keep those under conditionals to prevent unnecessary data from being fetched.
We’re going to have to use something new here. Let’s condense those conditionals into a scope:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Noted that keyword arguments would be very unhappy with us using if
there, making it a no-go.
Which allows us to write a much clearer controller:
1 2 3 4 5 6 7 8 9 10 |
|
Through just a few simple scoping mechanisms, we can trim down our controllers while still getting a very useful search from vanilla rails.