Josh McArthur

Finding records by ID with Ransack

29 Oct 2013

Ransack is one of my go-to Rubygems, especially for admin applications. It provides a really simple interface to building up complex filtering and ‘searching’ of many records. Check out the README for more information about how it all works - this post covers a specific problem case of Ransack.

In Rails, we are often subtely educated that the ID of the record doesn’t really matter to anyone - obviously it’s necessary, but for the most part, it just sits there, auto-incrementing. Every so often though, a use case comes along where the ID does matter. When this happens, there’s a bit of a gotcha with Ransack, where searching will just not work.

The reason it doesn’t work, is because the ID column is (usually) an integer column, not a varchar (string) - so many of the search predicates that Ransack applies to the column break (since you can’t do things like ILIKE on an integer). When I ran into this problem, I thought I’d have to delve deep into how Ransack works to figure out a solution - but as it turns out, support for manipulating column data is already built into Ransack, and there was a perfect solution described in this Github issue:

Essentially, Ransack, provides a ransacker method in our ActiveRecord models which can be used for any transformations that are necessary for a particular column. In this case, we’re using some PostgreSQL functions - the inner function to convert the integer ID column to a string, and the outer function to remove whitespace from the string produced by the inner function (since that function pads the converted number with whitespace). This means that each of our ID column values will be automatically cast to a searchable string by PostgreSQL, via Ransack, allowing us to use the following predicates without any further work:

A note on peformance

I should note that this solution may not be the best for your situation - obviously, casting each column value every time a search is done takes more work than just querying the column’s value directly, and so you should consider alternatives. If a fast search is integral to your application, perhaps it would be a good idea to add an id_string column to your database table that mirrors the ID column, but is a natively-searchable string that will not require casting. If you are after a quick and easy solution though, and search is more of a secondary function, then what I’ve laid out above should work perfectly for you!