Why are Rails model association results not naturally ActiveRecord::Relations?

前端 未结 2 1946
执笔经年
执笔经年 2020-12-16 00:20

I\'m using Rails 3.2.0

Let\'s say I have:

class Comment < ActiveRecord::Base
  has_many :articles
end

c1 = Comment.last

then

相关标签:
2条回答
  • 2020-12-16 01:01

    Because when you define association, it places in your model:

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

    .reader() returns AssociationProxy, which removes the .class method and delegates unknown methods to @target through .method_missing.

    0 讨论(0)
  • 2020-12-16 01:11

    It is an ActiveRecord::Relation, but Rails is intentionally lying to you. You can see this already in the method calls, and continue to see it by calling ancestors, which includes a slew of ActiveRecord classes:

    c1.articles.ancestors.select { |c| c.to_s =~ /ActiveRecord/ }.size  #=> 35
    

    which shows that it is very much not an Array.

    This happens because what you’re getting back when calling c1.articles is an ActiveRecord::Associations::CollectionProxy*, which undefines class (along with many other methods). This means that class gets delegated via its method_missing, which sends it to target. As we can see, the class of target here is, in fact, Array:

    c1.articles.target.class  #=> Array
    

    That is where c1.articles.class comes from. Nevertheless, it is an ActiveRecord::Relation.

    * We can verify that it is indeed an ActiveRecord::Associations::CollectionProxy by calling Ruby’s original class method on the object in question: Object.instance_method(:class).bind(c1.articles).call. This is a nice trick to verify that the object is not trying to pretend to be of a different class.

    0 讨论(0)
提交回复
热议问题