Kev*_*erg 5 ruby activerecord method-chaining
让我为你想象一下.
class Product < ActiveRecord::Base
end
Product.first.title
#=> "My sample product"
Run Code Online (Sandbox Code Playgroud)
这里没什么特别的.只是一个简单的方法调用.现在看一下下面的例子.
class Product < ActiveRecord::Base
def method_missing
end
end
Product.first.title
#=> nil
Product.first
Product.first.title
#=> "My sample product"
Run Code Online (Sandbox Code Playgroud)
这怎么可能?在某种程度上,他们确定方法链的结束并采取行动?至少这就是我的理论.
谁能解释这种行为?
你看到了一个irb
用来调查事物的工件.
当你这样说:
> Product.first.title
#=> nil
Run Code Online (Sandbox Code Playgroud)
你method_missing
将被调用懒惰加载title
方法,你得到nil
.
当你这样说:
> Product.first
Run Code Online (Sandbox Code Playgroud)
你实际上是这样做的:
> p = Product.first; puts p.inspect
Run Code Online (Sandbox Code Playgroud)
将加载第一个Product实例,然后irb
将调用inspect
它,AR将在此过程中添加访问器方法.结果是Product现在有了一个title
方法.因此,这样做:
> Product.first
> Product.first.title
Run Code Online (Sandbox Code Playgroud)
不会打电话给你method_missing
,因为有一个真正的title
方法Product.first.title
可以打电话.
如果你再试这样:
> Product.first; nil
> Product.first.title
Run Code Online (Sandbox Code Playgroud)
你会看到两个nil
.
就链接而言,ActiveRecord并没有真正检测到结束,只是某些方法调用自然需要来自数据库的真实数据而有些则不需要.
如果您调用where
,order
或任何其他查询方法,您将获得ActiveRecord :: Relation实例,并且您可以在该关系对象上链接更多查询方法和范围.例如,where
(ActiveRecord :: Relation通过包含ActiveRecord :: QueryMethods获得)如下所示:
def where(opts, *rest)
return self if opts.blank?
relation = clone
relation.where_values += build_where(opts, rest)
relation
end
Run Code Online (Sandbox Code Playgroud)
所以它只是制作当前查询的副本,为副本添加一些内容,并为您提供副本.
如果你打电话first
,last
,to_a
,all
,任何的可枚举的方法(即调用each
),...那么你问的具体实例和ActiveRecord的将要执行查询来实现问题的模型实例(一个或多个).例如,ActiveRecord::Relation#to_a
看起来像这样:
def to_a
logging_query_plan do
exec_queries
end
end
Run Code Online (Sandbox Code Playgroud)
而且all
只不过是一个包装纸to_a
.
ActiveRecord并不真正知道链的末端在哪里,它只是不会从数据库中加载任何东西,直到它必须通过说出去并检索我一些数据来告诉它链在哪里结束.
归档时间: |
|
查看次数: |
912 次 |
最近记录: |