为什么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::CollectionProxyObject.instance_method(:class).bind(c1.articles).call 这是一个很好的技巧来validation对象不是试图假装是一个不同的类。

因为当您定义关联时,它会放在您的模型中:

 def #{name}(*args) association(:#{name}).reader(*args) end 

.reader()返回AssociationProxy,它删除.class方法并通过.method_missing将未知方法委托给@target