在Rails的has_many关系中默认使用一个范围

假设我有以下类

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有一个范围life_supportingSolarSystem has_many :planets 。 我想定义我的has_many关系,这样当我为所有相关planets询问planets ,自动应用solar_system支持范围。 本质上,我想solar_system.planets == solar_system.planets.life_supporting

要求

  • 我不想把scope :life_supportingPlanet

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

  • 我也想通过不必添加到SolarSystem来防止重复

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

目标

我想有类似的东西

has_many :planets, :with_scope => :life_supporting

编辑:工作

正如@phoet所说,使用ActiveRecord可能无法实现默认的作用域。 但是,我发现了两个潜在的解决方法。 两者都防止重复。 第一个,虽然长,保持明显的可读性和透明度,第二个是帮助types的方法谁输出是明确的。

 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 

另一个更清洁的解决scheme是简单地将以下方法添加到SolarSystem

 def life_supporting_planets planets.life_supporting end 

并在你使用solar_system.life_supporting_planets地方使用solar_system.planets

既不回答这个问题,所以我只是把他们放在这里作为解决办法应该是其他人遇到这种情况。

在Rails 4中, Associations有一个可选的scope参数,它接受一个应用于Relation的lambda(参考ActiveRecord :: Associations :: ClassMethods的doc)

 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 

在Rails 3中, where_values解决方法有时可以通过使用where_values_hash来处理,其中的条件是由多个where或hash(这里不是这种情况)定义的。

 has_many :planets, conditions: Planet.life_supporting.where_values_hash 

我刚刚深入了解ActiveRecord,看起来好像是否可以通过has_many的当前实现来实现。 你可以传递一个块:conditions但是这仅限于返回条件散列,而不是任何forms的东西。

一个非常简单和透明的方法来实现你想要的(我想你要做的)是在运行时应用范围:

  # foo.rb def bars super.baz end 

这远远不是你所要求的,但它可能只是工作;)