为什么Rails模型关联结果不是自然的ActiveRecord :: Relations?

New*_*ria 12 activerecord types lazy-loading ruby-on-rails

我正在使用Rails 3.2.0

比方说我有:

class Comment < ActiveRecord::Base
  has_many :articles
end

c1 = Comment.last
Run Code Online (Sandbox Code Playgroud)

然后

c1.articles.class
# => Array

c1.articles.where('id NOT IN (999999)').class
# => ActiveRecord::Relation    
Run Code Online (Sandbox Code Playgroud)

为什么关联的结果不是一种类型ActiveRecord::Relation

它显然是/ 在某个时候:

c1.articles.to_orig
# undefined method `to_orig' for #<ActiveRecord::Relation:0x007fd820cc80a8>

c1.articles.class
# => Array
Run Code Online (Sandbox Code Playgroud)

某些评估作用于ActiveRecord :: Relation对象,但检查该类会给出不同的类型.


特别是,当merge用于连接多个查询时,这会破坏构建延迟加载的查询.

And*_*all 15

这是一个ActiveRecord::Relation,但Rails故意骗你.您可以在方法调用中看到这一点,并通过调用继续查看它ancestors,其中包括一系列ActiveRecord类:

c1.articles.ancestors.select { |c| c.to_s =~ /ActiveRecord/ }.size  #=> 35
Run Code Online (Sandbox Code Playgroud)

这表明它不是一个Array.

这是因为你在调用时得到的c1.articlesActiveRecord::Associations::CollectionProxy*,它取消定义class(以及许多其他方法).这意味着,class通过被授权method_missing,这将其发送到target.我们可以看到,target这里的类实际上是Array:

c1.articles.target.class  #=> Array
Run Code Online (Sandbox Code Playgroud)

那就是c1.articles.class来自哪里.不过,它一个ActiveRecord::Relation.

*我们可以ActiveRecord::Associations::CollectionProxy通过class在相关对象上调用Ruby的原始方法来验证它确实是一个问题:Object.instance_method(:class).bind(c1.articles).call.这是一个很好的技巧来验证对象不是试图假装是一个不同的类.

  • 在整个星期与阵列服装中的CollectionProxy作战之后,找到这个问题/答案恢复了我的理智.:) (3认同)