假设我有以下课程
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_supporting
,SolarSystem
has_many :planets
。我想定义我的has_many关系,以便当我向solar_system
询问所有关联的planets
时,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
。
没有回答这个问题所以我只是把它们放在这里作为解决方案,如果其他人遇到这种情况。
答案 0 :(得分:112)
在Rails 4中,Associations
有一个可选的scope
参数,该参数接受应用于Relation
的lambda(参见ActiveRecord::Associations::ClassMethods的文档)
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
答案 1 :(得分:1)
我刚刚深入了解ActiveRecord,看起来如果可以通过has_many
的当前实现来实现这一点。你可以将一个块传递给:conditions
,但这仅限于返回条件的哈希,而不是任何类型的东西。
一种非常简单透明的方式来实现您想要的(我认为您正在尝试做的事情)是在运行时应用范围:
# foo.rb
def bars
super.baz
end
这远非你所要求的,但它可能会起作用;)
答案 2 :(得分:0)
在Rails 5中,以下代码可以正常工作...
class Order
scope :paid, -> { where status: %w[paid refunded] }
end
class Store
has_many :paid_orders, -> { paid }, class_name: 'Order'
end