Searching, sorting, and filtering in Rails controllers can be a pain. ElasticSearch and Solr are great, high-powered solutions, but are really big dependencies for a small app.
Luckily, Rails includes scopes, which can provide you with a lot of what you need for simple searching, filtering, and sorting. If you take advantage of scope chaining, you can build the features you want without taking on big dependencies or writing a bunch of repetitive search code yourself.
Searching with scopes
#index method on your RESTful controller that shows a table of products. The products can be active, pending, or inactive, are available in a single location, and have a name.
If you want to be able to filter these products, you can write some scopes:
Each of these scopes defines a class method on Product that you can use to limit the results you get back.
Your controller can use these scopes to filter your results:
And now you can show just the active products with names that start with ‘Ruby’.
Clearly, this needs some cleanup
You can see how this code starts to get unwieldy and repetitive! Of course, you’re using Ruby, so you can stuff this in a loop:
A more reusable solution
You can move this code into a module and include it into any model that supports filtering:
You now have filtering and searching of your models with one line in the controller and one line in the model. How easy is that? You can also get built-in sorting by using the built-in
order class method, but it’s probably a better idea to write your own scopes for sorting. That way you can sanity-check the input.
To save you some effort, I put
Filterable into a gist. Give it a try in your own project, It’s saved me a lot of time and code.
Update: Thanks to Jan Sandbrink for pointing something out: It’s easy to forget to whitelist params in
filtering_params. If you do forget, it can open your app up to serious security problems.
To avoid all that, instead of using scopes named
starts_with, I updated this article to those scopes are now named
filter_by_starts_with. They’re clearer and safer that way.
An important warning
Sending params to scopes is an easy way to get basic searching and filtering in your web app. But if you’re not careful, and accept whatever your users send you, your app could have some pretty nasty security bugs.
order is vulnerable to SQL injection. So if you’re using params to define your sort order, you should always check the column names your user is sending you and only allow values you know are safe.
The Rails SQL Injection site will help you learn about which ActiveRecord methods are vulnerable, so you can keep your app secure.
Do you learn better with video?
You can watch every step, from starting a brand new app to adding searching and filtering, in the companion screencast. We’ll create an app, fill it with sample data, add a search form, and hook it up. And you’ll get the source along with the videos, so you can refer back when you add simple searching and filtering to your own Rails apps.