12

Rails3.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 #<ActiveRecord::Relation:0x007fd820cc80a8>

c1.articles.class
# => Array

特定の評価はActiveRecord::Relationshipオブジェクトに作用しますが、クラスを検査すると異なるタイプが得られます。


merge特に、これを使用して複数のクエリを連結する場合、遅延読み込みクエリの構築が中断されます。

4

2 に答える 2

16

ですが、ActiveRecord::RelationRailsは意図的にあなたに嘘をついていますancestorsこれはメソッド呼び出しですでに確認でき、多数のActiveRecordクラスを含むを呼び出すことで引き続き確認できます。

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

これは、それが非常にではないことを示していますArray

c1.articlesこれは、呼び出したときに返されるのがActiveRecord::Associations::CollectionProxy*であり、(他の多くのメソッドとともに)定義されていないために発生します。classこれは、を介しclass委任され、に送信されることを意味します。ご覧のとおり、ここのクラスは実際には次のとおりです。method_missingtargettargetArray

c1.articles.target.class  #=> Array

そこc1.articles.classから来ています。それにもかかわらず、それですActiveRecord::Relation

*問題のオブジェクトに対してRubyの元のメソッドを呼び出すことにより、それが実際にであることを確認できます。これは、オブジェクトが別のクラスのふりをしようとしていないことを確認するための優れたトリックです。ActiveRecord::Associations::CollectionProxyclassObject.instance_method(:class).bind(c1.articles).call

于 2012-12-28T18:10:35.867 に答える
2

関連付けを定義すると、モデルに次のように配置されるためです。

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

.reader()はAssociationProxyを返します。これにより、.classメソッドが削除され、.method_missingを介して不明なメソッドが@targetに委任されます

于 2012-12-28T17:54:15.523 に答える