Ruby on rails 作用域的真正好处是什么

Ruby on rails 作用域的真正好处是什么,ruby-on-rails,activerecord,scope,Ruby On Rails,Activerecord,Scope,我已经看了10多页,试图找到作用域相对于任何其他返回ActiveRecord::Relation的ActiveRecord类方法的优势 例如,在下面的示例中,为什么作用域比下面做同样事情的备选方案更好: #scope :pat1, lambda {{:conditions => ["name like ?", 'J%']}} #scope :pat2, lambda {{:conditions => ["id > 5"]}} def self.p

我已经看了10多页,试图找到作用域相对于任何其他返回ActiveRecord::Relation的ActiveRecord类方法的优势

例如,在下面的示例中,为什么作用域比下面做同样事情的备选方案更好:

  #scope :pat1,  lambda {{:conditions => ["name like ?", 'J%']}}    
  #scope :pat2,  lambda {{:conditions => ["id  > 5"]}}  

  def self.pat1
    where("name like ?", 'J%')
  end  

  def self.pat2 
    where("id  > 5")
  end  

  def patx 
    self.class.pat1.pat2.first
  end
文档一再指出作用域是有益的,因为它们可以被链接

“所有作用域方法都将返回ActiveRecord::Relation对象,该对象将允许对其调用其他方法(如其他作用域)。” -

“作用域优于普通类方法的主要原因是它们可以与其他方法链接”

…但上述替代方案也可以链接起来产生相同的结果


我只是想知道这里是否有皇帝的新衣。即使从句法的角度来看,似乎也没有什么好处。它们更快吗?一些消息来源含糊其辞地暗示了这一点

是的,它们是语法上的捷径,基本上代表了您找到的方法。
为什么更好?
最直接的效果是,2行代码比9行代码更易于阅读和维护


Rails总是寻求一种枯燥的方法,在这里重复的
def self.method end
掩盖了实际的代码

当您编写一个作用域时,它实际上也在做同样的事情。以下是Rails源代码的外观:

    def scope(name, scope_options = {})
      name = name.to_sym
      valid_scope_name?(name)
      extension = Module.new(&Proc.new) if block_given?

      scope_proc = lambda do |*args|
        options = scope_options.respond_to?(:call) ? unscoped { scope_options.call(*args) } : scope_options
        options = scoped.apply_finder_options(options) if options.is_a?(Hash)

        relation = scoped.merge(options)

        extension ? relation.extending(extension) : relation
      end

      singleton_class.send(:redefine_method, name, &scope_proc)
    end
在这种情况下,作用域的好处是它们是定义查询的惯用方式,在某些情况下,代码行更少,并且您可以进行扩展

源代码中的示例如下所示:

scope :red, where(:color => 'red') do
  def dom_id
    'red_shirts'
  end
end

它允许您调用
Model.red.dom\u id

ActiveRecord作用域实际上只是一种最佳实践中的语法糖衣,如前所述


在Rails的2.x时代,当它们被称为“named_scope”时,它们更为重要。它们允许轻松链接生成查询的条件。通过使用Arel改进Rails3.x,可以很容易地为查询关系创建函数,如您所述。Scopes只是为可链接的预定义查询提供了一个简单而优雅的解决方案。将所有作用域放在模型的顶部可以提高可读性,并有助于展示如何使用模型。

作用域和返回关系的类方法之间有一些非常有趣的区别

  • 对于具有简单的
    param.present?
    check的作用域,更容易处理nil参数,对于类方法,如果param会导致nil关系,则必须显式返回非nil关系

  • 作用域比类方法更容易扩展。只需传递一个块(例如处理分页)即可添加方法。类方法可以扩展,但不能如此优雅


  • 要了解详细情况,请参阅。

    感谢您和肖恩·希尔确认这不是速度问题。上面的railstutorial.org链接一开始就明确指出,他们使用作用域的替代实现在某种程度上更快,但显然与使用作用域的替代实现无关。我假设Arel意味着ActiveRecord::Relation。好啊对我来说,语法上的好处似乎是有争议的。但如果他们在做一些标准方法在以前的版本中无法做到的事情,那么这就是原因。rails使用更好的语法是很重要的。不是针对第1天(甚至100天)的代码库,而是针对第1000天的代码库。