mahi-man
mahi-man

Reputation: 4686

Rails 4 ActiveRecord scope to query different date field based on whether it exists

I have a VoyageLeg model that has many date fields. I have an instance method as below to get one of the dates based on whether it has been populated:

def calc_arrival_date
  if ada
    ada #return actual date of arrival
  elsif updated_eda
    updated_eda #return updated estimated date of arrival
  else
    eda #return estimated date of arrival
  end
end

I also have a Voyage model that has_many voyage_legs. How would I create a scope on the Voyage model would would reference the calc_arrival_date, or alternatively do the same logic regarding which date to query in the scope?

I.e. I would like to be able to have a scope on the Voyage that would do something like:

scope :archived, -> { joins(:voyage_legs).where("voyage_legs.calc_arrival_date < ?", Time.zone.now) }

Upvotes: 0

Views: 84

Answers (2)

mahi-man
mahi-man

Reputation: 4686

I ended up using part of your code @Shabini Rajadas, but combined the date clause inside the logic as a class method on the VoyageLeg model as follows:

def self.departed
  where("CASE WHEN voyage_legs.add IS NOT NULL THEN
      voyage_legs.add < :now
    WHEN voyage_legs.updated_edd IS NOT NULL THEN
      voyage_legs.updated_edd < :now
    WHEN voyage_legs.add IS NULL and voyage_legs.updated_edd IS NULL THEN
      voyage_legs.edd  < :now END", now: Time.zone.now.to_date)
end

Then I can filter Voyages like Voyage.joins(:voyage_legs).merge(VoyageLeg.departed)

Upvotes: 0

Shabini Rajadas
Shabini Rajadas

Reputation: 771

To achieve your request, a little more extra work to be done.

The scope method,

scope :archived, -> {joins(:voyage_legs).select('(CASE WHEN voyage_legs.ada IS NOT NULL THEN voyage_legs.ada WHEN voyage_legs.updated_eda IS NOT NULL THEN voyage_legs.updated_eda WHEN voyage_legs.ada IS NULL and voyage_legs.updated_eda IS NULL THEN voyage_legs.eda END) as calc_arrival_date')}

And a little calculations on the result,

result = Voyage.archived.select { |b| b.calc_arrival_date.to_datetime < Time.zone.now  }

Upvotes: 1

Related Questions