Ruby ActiveRecord如何检测链中的最后一个方法调用?
让我为你设想一下Ruby ActiveRecord如何检测链中的最后一个方法调用?,ruby,activerecord,method-chaining,Ruby,Activerecord,Method Chaining,让我为你设想一下 class Product < ActiveRecord::Base end Product.first.title #=> "My sample product" 类产品“我的样品产品” 这里没什么特别的。只是一个简单的方法调用。现在看看下面的例子 class Product < ActiveRecord::Base def method_missing end end Product.first.title #=> nil Prod
class Product < ActiveRecord::Base
end
Product.first.title
#=> "My sample product"
类产品“我的样品产品”
这里没什么特别的。只是一个简单的方法调用。现在看看下面的例子
class Product < ActiveRecord::Base
def method_missing
end
end
Product.first.title
#=> nil
Product.first
Product.first.title
#=> "My sample product"
类产品零
产品优先
产品名称
#=>“我的样品产品”
这怎么可能?在某种程度上,他们决定了方法链的终点,并据此采取行动?至少这是我的理论
有人能解释这种行为吗 你看到了一个使用
irb
调查事情的假象
当你这么说的时候:
> Product.first.title
#=> nil
> Product.first
您的方法\u missing
将被调用以延迟加载title
方法,您将得到nil
当你这么说的时候:
> Product.first.title
#=> nil
> Product.first
实际上,您正在这样做:
> p = Product.first; puts p.inspect
> Product.first
> Product.first.title
第一个产品实例将被加载,然后irb
将在其上调用inspect
,AR将在此过程中添加访问器方法。结果是产品现在将有一个title
方法。因此,这样做:
> p = Product.first; puts p.inspect
> Product.first
> Product.first.title
不会调用您的方法\u missing
,因为产品将有一个真正的title
方法。首先,要调用title
如果您再次这样尝试:
> Product.first; nil
> Product.first.title
def where(opts, *rest)
return self if opts.blank?
relation = clone
relation.where_values += build_where(opts, rest)
relation
end
def to_a
logging_query_plan do
exec_queries
end
end
您将看到两个nil
s
就链接而言,ActiveRecord并没有真正检测到结束,只是有些方法调用自然需要来自数据库的真实数据,而有些则不需要 如果调用
where
、order
或任何其他查询方法,则会返回一个实例,并且可以在该关系对象上链接更多查询方法和范围。例如,(ActiveRecord::Relation通过包含获得的)如下所示:
> Product.first; nil
> Product.first.title
def where(opts, *rest)
return self if opts.blank?
relation = clone
relation.where_values += build_where(opts, rest)
relation
end
def to_a
logging_query_plan do
exec_queries
end
end
因此,它只是复制当前查询,在副本中添加一些内容,然后返回副本
如果您调用第一个
,最后一个
,到a
,所有
,任何方法(即调用每个
)。。。然后,您询问特定实例,ActiveRecord必须执行查询以实现所讨论的模型实例。例如,如下所示:
> Product.first; nil
> Product.first.title
def where(opts, *rest)
return self if opts.blank?
relation = clone
relation.where_values += build_where(opts, rest)
relation
end
def to_a
logging_query_plan do
exec_queries
end
end
它只不过是对a
的包装而已
ActiveRecord并不真正知道链的末端在哪里,它只是在必须加载之前不会从数据库中加载任何内容,因此您可以通过说“前进并检索一些数据”来告诉它链的末端。我认为它确实检测到链的末端:在那里您不会返回finder代理对象!这不是问题所在。问题是为什么
Product.first.title
返回nil
,直到调用Product.first
,当在模型中使用method\u missing
时。一旦你调用了产品。首先
title返回我的示例博客
@user544941:啊,我知道他在问什么了:是什么替换或绕过了他的方法\u缺少
@user544941:我现在有正确的问题了吗?我想他只是被irb
在背后做的事情弄糊涂了。顺便说一句,谢谢你指出困惑。