90

假设我有以下课程

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 关系,以便当我要求 a solar_systemfor all associatedplanets时,life_supporting会自动应用范围。本质上,我想要solar_system.planets == solar_system.planets.life_supporting.

要求

  • 不想换成scope :life_supporting_ Planet_

    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 可能无法实现默认范围。但是,我发现了两个潜在的解决方法。两者都防止重复。第一个虽然很长,但保持了明显的可读性和透明度,第二个是辅助类型方法,其输出是显式的。

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

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

def life_supporting_planets
  planets.life_supporting
end

并在solar_system.life_supporting_planets任何你想使用的地方使用solar_system.planets.

两者都没有回答这个问题,所以我只是把它们放在这里,以防其他人遇到这种情况。

4

3 回答 3

140

在 Rails 4 中,Associations有一个可选scope参数,该参数接受应用于Relation(参见ActiveRecord::Associations::ClassMethods的文档)的 lambda

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或散列定义(这里不是这种情况)。

has_many :planets, conditions: Planet.life_supporting.where_values_hash
于 2013-10-22T15:05:44.340 回答
24

在 Rails 5 中,以下代码可以正常工作...

  class Order 
    scope :paid, -> { where status: %w[paid refunded] }
  end 

  class Store 
    has_many :paid_orders, -> { paid }, class_name: 'Order'
  end 
于 2019-03-05T17:32:12.493 回答
1

我刚刚深入研究了 ActiveRecord,但目前的has_many. 您可以将块传递给,:conditions但这仅限于返回条件哈希,而不是任何类型的 arel 东西。

实现您想要的(我认为您正在尝试做的)的一种非常简单且透明的方法是在运行时应用范围:

  # foo.rb
  def bars
    super.baz
  end

这与您的要求相去甚远,但它可能会起作用;)

于 2012-07-24T19:01:13.943 回答