为什么Rails模型关联结果不是自然的ActiveRecord :: Relations?
我正在使用Rails 3.2.0
假设我有:
class Comment < ActiveRecord::Base has_many :articles end c1 = Comment.last
然后
c1.articles.class # => Array c1.articles.where('id NOT IN (999999)').class # => ActiveRecord::Relation
为什么关联的结果不是 ActiveRecord::Relation
的类型?
它显然是/ 在某个时候 :
c1.articles.to_orig # undefined method `to_orig' for # c1.articles.class # => Array
某些评估作用于ActiveRecord :: Relation对象,但检查该类会给出不同的类型。
特别是,当使用merge
来连接多个查询时,这会破坏构建延迟加载的查询。
它是一个ActiveRecord::Relation
,但是Rails故意骗你 。 您可以在方法调用中看到这一点,并通过调用ancestors
来继续查看它,其中包括一系列ActiveRecord类:
c1.articles.ancestors.select { |c| c.to_s =~ /ActiveRecord/ }.size #=> 35
这表明它不是一个Array
。
发生这种情况是因为在调用c1.articles
时你得到的是ActiveRecord::Associations::CollectionProxy
*,它c1.articles
定义class
(以及许多其他方法)。 这意味着class
通过其method_missing
进行委派,该方法将其发送到target
。 我们可以看到,这里的target
类实际上是Array
:
c1.articles.target.class #=> Array
这就是c1.articles.class
来源。 然而,它是一个ActiveRecord::Relation
。
* 我们可以通过在相关对象上调用Ruby的原始class
方法来validation它确实是一个ActiveRecord::Associations::CollectionProxy
: Object.instance_method(:class).bind(c1.articles).call
。 这是一个很好的技巧来validation对象不是试图假装是一个不同的类。
因为当您定义关联时,它会放在您的模型中:
def #{name}(*args) association(:#{name}).reader(*args) end
.reader()返回AssociationProxy,它删除.class方法并通过.method_missing将未知方法委托给@target 。