ruby on rails命名范围实现

Hei*_* Yu 3 ruby named-scope ruby-on-rails

来自Agile Web Development With Rails一书

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

   named_scope :checks, :conditions => {:pay_type => :check}
end
Run Code Online (Sandbox Code Playgroud)

该声明

orders = Orders.checks.last_n_days(7)
Run Code Online (Sandbox Code Playgroud)

只会对数据库进行一次查询.

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

为了能够链接这样的方法,named_scope生成的函数必须返回自己或者可以进一步调整范围的对象.但Ruby如何知道它是最后一个函数调用,它现在应该查询数据库?

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

Mil*_*ota 7

在named_scope魔法中使用了两种技巧(或者你将使用的模式).

代理模式 - 在类或关联上调用命名范围方法始终返回ActiveRecord :: NamedScope :: Scope类的实例,而不是已过滤的AR对象的集合.这种模式非常有用,有时会使事情变得模糊,因为代理对象本质上是矛盾的.

延迟加载 - 由于延迟加载(在此上下文中意味着 - 只在必要时才访问数据库)命名范围可以链接到需要使用范围定义的集合时.每当您请求底层的colleciton时,都会评估所有链接的范围并执行数据库查询.

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