Use the default scope for the Rails has_many relationship

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 the scope of life_supporting and SolarSystem has_many :planets . I would like to define my has_many relationship, so when I set the solar_system for all related planets , the scope of life_supporting automatically applied. Essentially, I would like solar_system.planets == solar_system.planets.life_supporting .

Requirements

  • I want to not change scope :life_supporting in Planet to

    default_scope where('distance_from_sun > ?', 5).order('diameter ASC')

  • I would also like to prevent duplication without adding to SolarSystem

    has_many :planets, :conditions => ['distance_from_sun > ?', 5], :order => 'diameter ASC'

goal

I would like to have something like

has_many :planets, :with_scope => :life_supporting

Edit: work around

As @phoet said, it may not be possible to reach the default area using ActiveRecord. However, I found two potential problems. Both prevent duplication. The first, although lengthy, retains obvious readability and transparency, and the second is an auxiliary method, the output of which is obvious.

 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 that is much cleaner is to simply add the following method to SolarSystem

 def life_supporting_planets planets.life_supporting end 

and use solar_system.life_supporting_planets wherever you would use solar_system.planets .

None of the answers answer the question, so I just put them here as work if someone else comes across this situation.

+58
activerecord ruby-on-rails-3 has-many
Jul 24 '12 at 17:53
source share
2 answers

Rails 4 Associations has an optional scope parameter that accepts lambda, which applies to Relation (see the document for ActiveRecord :: associations :: class methods)

 class SolarSystem < ActiveRecord::Base has_many :planets, -> { life_supporting } end class Planet < ActiveRecord::Base scope :life_supporting, -> { where('distance_from_sun > ?', 5).order('diameter ASC') } end 

In Rails 3, the where_values can sometimes be improved with where_values_hash , which handles better areas of application where conditions are defined by several where or a hash (not here).

 has_many :planets, conditions: Planet.life_supporting.where_values_hash 
+91
Oct 22 '13 at 15:05
source share

I just had a deep dive in ActiveRecord and it does not look if this can be achieved with the current has_many implementation. you can pass the block to :conditions , but this is limited to returning a hash of the conditions, not some isl stuff.

A really simple and transparent way to achieve what you want (which I think you're trying to do) is to apply the scope at runtime:

  # foo.rb def bars super.baz end 

this is far from what you are asking for, but it might work;)

+1
Jul 24 '12 at 19:01
source share



All Articles