Local Dates in Ransack

I was recently tasked with moving the search functionality of an internal admin tool away from an external service and onto the application’s database. The tool is a Ruby on Rails application that runs against a Postgres instance. Being fairly new to Rails and the community, it was suggested that I try Ransack, a project that generates SQL-queries from a simple form. This was the exact fit for our use case, and then documentation was quite helpful in translating the existing search form into a Ransack-compliant form.

One small issue that wasn’t solved out of the box was the ability to find all row instances that occurred on a specific local date (with the locality not being defined by the data). Our data currently spans numerous timezones, but our admin teams need to see all the upcoming data for their current day. A common problem, but one seemingly not supported out of the box by Ransack. We need to generate our own custom search function using Arel predicate methods. Ransack provided a nice how-to for this process.

I ended up with the following in config/initializers/ransack.rb:

Ransack.configure do |config|

  config.add_predicate 'date_equals_local_date',
    arel_predicate: 'between',
    formatter: proc { |v| v.to_date.beginning_of_day.change(offset: Time.zone.utc_offset)..v.to_date.end_of_day.change(offset: Time.zone.utc_offset) },
    validator: proc { |v| v.present? },
    type: :string

end

This simply grabs the application’s timezone and sets it as the offset for the query on date field, then creates a BETWEEN query on that field. To use it in a form, you’d specify the field you’d like to generate this query for. Given we have a field called booking_time, our search form would include something like this:

= f.date_picker :booking_time_date_equals_local_date

Simple and straightforward. I was impressed by Ransack’s ability to get up and running quickly while also supporting extendibility in a simple fashion.