20

我想知道ActiveRecord::Associations::CollectionProxy和之间的区别ActiveRecord::AssociationRelation

class Vehicle < ActiveRecord::Base
  has_many :wheels
end

class Wheel < ActiveRecord::Base
  belongs_to :vehicle
end

所以如果我这样做:

v = Vehicle.new

v.wheels # => #<ActiveRecord::Associations::CollectionProxy []>

v.wheels.all # => #<ActiveRecord::AssociationRelation []>

我不知道它们之间有什么区别,为什么要这样实现?

4

2 回答 2

22

ActiveRecord::Relation在转换为查询并执行之前是简单的查询对象,CollectionProxy另一方面更复杂一些。

首先你得到关联扩展,你可能看到了像这样的东西,假设一个书店模型有很多书

class Store < ActiveRecord::Base
  has_many :books do
    def used
      where(is_used: true)
    end
  end
end

通过这种方式,您可以使用如下所示的语法来调用商店中的旧书

Store.first.books.used

但这是最基本的用途,您可以使用在集合代理中向您公开的属性,即owner,reflectiontarget

所有者

owner提供对持有关联的父对象的引用

反射

reflection对象是关联的一个实例ActiveRecord::Reflection::AssocciationReflection并包含关联的所有配置选项。

目标

target是关联集合对象(或当has_one和时的单个对象belongs_to)。

使用这些方法,您可以在关联扩展中执行一些条件,例如,如果我们有一个博客,我们会将所有已删除帖子的访问权限授予管理员用户(我知道的蹩脚示例)

Class Publisher < ActiveRecord::Base
  has_many :posts do
    def deleted
      if owner.admin?
        Post.where(deleted: true)
      else
        where(deleted: true)
      end
    end
  end
end

您还可以访问另外两个方法resetreload,第一个 ( reset) 清除缓存的关联对象,第二个 ( reload) 更常见,用于reset然后从数据库加载关联对象。

我希望这能解释CollectionProxy上课是多么有用

于 2015-11-13T19:05:57.273 回答
14

好的。区别很简单。

根据您的示例进行解释:

中的关联代理v.wheels具有:

  • v@owner中的对象;
  • 将其轮子集合为@target;
  • @reflection 对象代表一个:has_many宏。

来自文档

Active Record 中的关联代理是@owner 和@target 之间的中间人。 @target 对象在需要时才会加载。

v = Vehicle.new
v.wheels # we are not sending any methods to @target object (collection of wheels)
# => #<ActiveRecord::Associations::CollectionProxy []>

这意味着,只要您在 @target 对象(wheels在我们的例子中保存集合)上调用任何方法,@target 就会被加载,并且它变成ActiveRecord_AssociationRelation.

v.wheels.all # sending the `all` method to @target (wheels)
# => #<ActiveRecord::AssociationRelation []>
于 2015-11-13T18:09:08.977 回答