Search code examples
ruby-on-railspostgresqlactiverecordarel

Activerecord query with condition on following record


I have an Event model, with a starts attribute for a start date. An event ends when the following event begins (the last event goes on indefinitely). I would like to have a query that returns the events starting from the event that contains a given date dd:

Event.since(Date.today)

should return the current event and the following ones.

I could easily do that with two queries:

first=Event.where(starts: -Float::INFINITY..Date.today).order(starts: :asc).last
Event.where(starts: first.starts..Float::INFINITY)

but is there anything more efficient?

This is with postgresql, in case this makes a difference


Solution

  • class Event < ApplicationRecord
      # @see https://devhints.io/arel
      def self.after(time = Time.current)
        col = arel_table[:starts]
        sub_query = arel_table.project(col)
                              .where(col.lt(time))
                              .order(col.asc)
                              .take(1)
        where(col.gt(sub_query))
      end
    end
    

    This generates a subquery in the where clause:

    SELECT "events".* FROM "events" 
    WHERE "events"."starts" > (SELECT "events"."starts" FROM "events" WHERE "events"."starts" < '2020-03-08 17:32:16.602529' ORDER BY "events"."starts" ASC LIMIT 1) LIMIT $1