Here goes another round of wrapping my head around what rails associations are looking for.
This time, I’m trying to scope a collection on the other side of a has_many :through to an attribute on that model.
Contrived exhibit A:
class Gym < ActiveRecord::Base
# gym has a boolean "open"
end
class TrainerGym < ActiveRecord::Base
has_one :trainer
has_one :gym
end
class Trainer < ActiveRecord::Base
has_many :trainer_gyms
has_many :gyms, through: :trainer_gyms
end
I want to create an association of `open_gyms` that my `Trainer` is connected to.
The end result looks like this for the `Trainer` model:
class Trainer < ActiveRecord::Base
has_many :trainer_gyms
has_many :gyms, through: :trainer_gyms
has_many :open_trainer_gyms ->{ includes(:gym).where(gyms: {open: true}) }, class_name: TrainerGym
has_many :open_gyms, through: :open_trainer_gyms, source: :gym
end
The scope:
->{ includes(:gym).where(gyms:{open: true}) }
`includes` the association `gym` from `TrainerGym`. The `where` clause specifies the table `gyms` and the nested hash is the condition on `gyms` to match (`{open: true}`).
The `class_name: TrainerGym` tells the association `open_trainer_gyms` that it is a collection of the model `TrainerGym`, since that cannot be determined by reflection/inflection magic.
The `open_gyms` association piggy-backs the `open_trainer_gyms` association, but the `:through` relationship needs to be told that the `gym` association on `TrainerGym` is how it gets to the other side, since `open_gyms` can't be converted to `gym` automatically by the reflection and inflection magic.