Let's say I have the following classes
class SolarSystem < ActiveRecord::Base
has_many :planets
end
class Planet < ActiveRecord::Base
scope :life_supporting, where('distance_from_sun > ?', 5).order('diameter ASC')
end
Planet
has a scope life_supporting
and SolarSystem
has_many :planets
. I would like to define my has_many relationship so that when I ask a solar_system
for all associated planets
, the life_supporting
scope is automatically applied. Essentially, I would like solar_system.planets == solar_system.planets.life_supporting
.
Requirements
I do not want to change
scope :life_supporting
inPlanet
todefault_scope where('distance_from_sun > ?', 5).order('diameter ASC')
I'd also like to prevent duplication by not having to add to
SolarSystem
has_many :planets, :conditions => ['distance_from_sun > ?', 5], :order => 'diameter ASC'
Goal
I'd like to have something like
has_many :planets, :with_scope => :life_supporting
Edit: Work Arounds
As @phoet said, it may not be possible to achieve a default scope using ActiveRecord. However, I have found two potential work arounds. Both prevent duplication. The first one, while long, maintains obvious readability and transparency, and the second one is a helper type method who's output is explicit.
class SolarSystem < ActiveRecord::Base
has_many :planets, :conditions => Planet.life_supporting.where_values,
:order => Planet.life_supporting.order_values
end
class Planet < ActiveRecord::Base
scope :life_supporting, where('distance_from_sun > ?', 5).order('diameter ASC')
end
Another solution which is a lot cleaner is to simply add the following method to SolarSystem
def life_supporting_planets
planets.life_supporting
end
and to use solar_system.life_supporting_planets
wherever you'd use solar_system.planets
.
Neither answers the question so I just put them here as work arounds should anyone else encounter this situation.
In Rails 5, the following code works fine...
In Rails 4,
Associations
have an optionalscope
parameter that accepts a lambda that is applied to theRelation
(cf. the doc for ActiveRecord::Associations::ClassMethods)In Rails 3, the
where_values
workaround can sometimes be improved by usingwhere_values_hash
that handles better scopes where conditions are defined by multiplewhere
or by a hash (not the case here).i just had a deep dive into ActiveRecord and it does not look like if this can be achieved with the current implementation of
has_many
. you can pass a block to:conditions
but this is limited to returning a hash of conditions, not any kind of arel stuff.a really simple and transparent way to achieve what you want (what i think you are trying to do) is to apply the scope at runtime:
this is far from what you are asking for, but it might just work ;)