【问题标题】:ruby on rails named scope implementationruby on rails 命名范围实现
【发布时间】:2010-04-09 13:14:58
【问题描述】:

来自《使用 Rails 进行敏捷 Web 开发》一书

class Order < ActiveRecord::Base
   named_scope :last_n_days, lambda { |days| {:conditions =>
      ['updated < ?' , days] } }

   named_scope :checks, :conditions => {:pay_type => :check}
end

声明

orders = Orders.checks.last_n_days(7)

将导致只对数据库进行一次查询。

rails 如何实现这一点?我是 Ruby 的新手,我想知道是否有一个特殊的构造允许这种情况发生。

为了能够像这样链接方法,named_scope 生成的函数必须返回自身或对象,而不是进一步限定范围。但是 Ruby 怎么知道它是最后一个函数调用并且它现在应该查询数据库呢?

我问这个是因为上面的语句实际上是查询数据库,而不仅仅是返回一个由链接产生的 SQL 语句。

【问题讨论】:

    标签: ruby-on-rails ruby named-scope


    【解决方案1】:

    named_scope 魔术中有两个技巧(或模式,如果你愿意的话)。

    代理模式 - 在类或关联上调用命名范围方法总是返回 ActiveRecord::NamedScope::Scope 类的实例,而不是过滤后的 AR 对象。这种模式虽然非常有用,但有时会让事情变得有些模糊,因为代理对象在本质上是矛盾的。

    延迟加载 - 由于延迟加载(在这种情况下意味着 - 仅在必要时才访问数据库)命名范围可以链接到您需要使用定义的集合时范围。每当您请求基础集合时,都会评估所有链式作用域并执行数据库查询。

    最后一点:在 IRB 中使用命名作用域(或任何使用某种委托的东西)时,需要牢记一件事。每次您按 Enter 键时,都会评估您之前编写的内容,并在返回值上调用 inspect 方法。在链式命名范围的情况下,虽然整个表达式被评估为一个 Scope 实例,但当 IRB 对其调用 inspect 方法时,将评估范围并触发数据库查询。这是因为inspect 方法是通过委托传播到底层集合的所有作用域对象。

    【讨论】:

      【解决方案2】:

      你可能想试试这个

      class Order < ActiveRecord::Base
      
        class << self
          def last_n_days(n)
            scoped(:conditions => ['updated < ?', days])
          end
          def checks
            scoped(:conditions => {:pay_type => :check})
          end
        end
      
      end
      

      用法一样

      @orders = Order.last_n_days(5)
      @orders = Order.checks
      @orders = Order.checks.last_n_days(5)
      

      这仍然可以完成您喜欢的所有延迟加载。也就是说,在您尝试访问记录之前,它不会进行查询。 奖励:兼容 Rails 3!

      Named Scopes Are Dead

      【讨论】:

        【解决方案3】:

        非常酷。我想在 Javascript 中做这样的事情,但 Javascript 的行为相当奇怪。

        声明:

        var x = SomeObject;
        

        不调用 SomeObject 的 toString() 函数。但声明:

        var x;
        x = SomeObject;
        

        按预期正确调用 toString() 函数。

        这可以防止 Javascript 通过链接来做一些很酷的事情。 =(

        【讨论】:

          猜你喜欢
          • 2011-01-24
          • 1970-01-01
          • 2018-08-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多