默认情况下,在Rails has_many关系上使用范围

Aar*_*ron 74 activerecord has-many ruby-on-rails-3

假设我有以下课程

class SolarSystem < ActiveRecord::Base
  has_many :planets
end

class Planet < ActiveRecord::Base
  scope :life_supporting, where('distance_from_sun > ?', 5).order('diameter ASC')
end
Run Code Online (Sandbox Code Playgroud)

Planet有范围life_supportingSolarSystem has_many :planets.我想定义我的has_many关系,这样当我询问solar_system所有关联时planets,life_supporting范围会自动应用.基本上,我想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可能无法实现默认范围.但是,我发现了两个潜在的工作.两者都可以防止重复.第一个是长期保持明显的可读性和透明度,第二个是助手类型方法,其输出是显式的.

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
Run Code Online (Sandbox Code Playgroud)

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

def life_supporting_planets
  planets.life_supporting
end
Run Code Online (Sandbox Code Playgroud)

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

既没有回答这个问题,所以我只是把它们放在这里作为解决方案,如果其他人遇到这种情况.

gre*_*ont 117

在Rails 4中,Associations有一个可选scope参数,它接受一个应用于的lambda Relation(参见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
Run Code Online (Sandbox Code Playgroud)

在Rails 3中,where_values有时可以通过使用where_values_hash更好的范围来处理变通范围,其中条件由多个where或散列定义(这里不是这种情况).

has_many :planets, conditions: Planet.life_supporting.where_values_hash
Run Code Online (Sandbox Code Playgroud)

  • @GrégoireClermont 这不再适用于 Rails 5 (2认同)

Mar*_*her 23

在 Rails 5 中,以下代码运行良好......

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

  class Store 
    has_many :paid_orders, -> { paid }, class_name: 'Order'
  end 
Run Code Online (Sandbox Code Playgroud)