Arslan Ali
Arslan Ali

Reputation: 17812

How to apply conditions on a child model's association from parent model in ActiveRecord?

I have the following models:

  1. Staff
  2. Seminar
  3. Schedule

Relations are simple:

class Staff < ApplicationRecord
  has_many :seminars
end

class Seminar < ApplicationRecord
  belongs_to :staff
  has_many :schedules
  has_many :future_schedules, -> { future }, class_name: 'Schedule'
  has_many :past_schedules,   -> { past }, class_name: 'Schedule'
end

class Schedule < ApplicationRecord
  belongs_to :seminar

  scope :future, -> { where('starts_at > ?', Time.now) }
  scope :past,   -> { where('ends_at > ?', Time.now) }
end

I can easily do: seminar.future_schedules & seminar.past_schedules, but here is the issue: I would like to have a way to get those seminars for a staff that have schedules in future.

What I have tried:

has_many :future_seminars, -> { future_schedules }, class_name: 'Seminar'

But the problem is: I can't pass future_schedules in above line, because it isn't a scope.

has_many :future_seminars, -> { where('schedules.starts_at > ?', Time.now) }, class_name: 'Seminar'

But it says: schedules.starts_at is not a column, and it is so. So is there anyway I can load schedules for seminars in advance using something like includes?

Upvotes: 2

Views: 345

Answers (2)

Ahmad Saleem
Ahmad Saleem

Reputation: 138

You can perhaps do something like this:

In Seminar model:

scope :future_seminars, -> { joins(:schedules).where("schedules.starts_at >", Time.current) }

In Staff model:

has_many :future_seminars, -> { future_seminars }, class_name: 'Seminar'

Also, I think there's a type in the scope for past schedules. It should be like this

scope :past, -> { where('ends_at < ?', Time.now) }

Upvotes: 2

David Aldridge
David Aldridge

Reputation: 52376

If you need a highly performant method then you may need to blend in some SQL.

Something like:

Staff.find(32).seminars.
               where(Schedule.where("schedules.seminar_id = seminars.id").
                              where("schedules.starts_at > ?", Time.now).exists)

Upvotes: 1

Related Questions