摘自《使用 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 语句。
在named_scope 魔法中使用了两种技巧(或者模式,如果你愿意的话)。
代理模式- 在类或关联上调用命名范围方法always返回 ActiveRecord::NamedScope::Scope 类的实例,而不是过滤的 AR 对象的集合。这种模式虽然非常有用,但有时会使事情变得模糊,因为代理对象本质上是矛盾的。
延迟加载- 由于延迟加载(在这种情况下意味着 - 仅在必要时才访问数据库),命名范围可以链接到您需要使用范围定义的集合时的点。每当您请求底层集合时,都会评估所有链接的范围并执行数据库查询。
最后一点:在 IRB 中使用命名范围(或任何使用某种委托的事物)时需要记住一件事。每次你按下 Enter 时,你之前写的东西都会被评估,并且inspect
方法在返回值上被调用。在链接命名作用域的情况下,尽管整个表达式被计算为 Scope 实例,但当 IRB 调用inspect
方法,评估范围并触发数据库查询。这是由于以下事实造成的:inspect
方法通过委托传播到所有作用域对象直至底层集合。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)