CollectionProxy 与 AssociationRelation
CollectionProxy vs AssociationRelation
我想知道 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 []>
我不知道它们之间有什么区别,为什么要这样实现?
好的。区别很简单。
根据您的示例进行解释:
v.wheels
中的关联代理有:
v
中的对象作为@owner;
- 它的轮子集合为@target;
- @reflection 对象表示一个
:has_many
宏。
来自docs:
Association proxies in Active Record are middlemen between the @owner
and the @target.
The @target object is not loaded until needed.
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 []>
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
、reflection
和target
所有者
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
您还可以访问另外两个方法 reset
和 reload
,第一个 (reset
) 清除缓存的关联对象,第二个 (reload
) 更常见,用于 reset
然后从数据库中加载关联对象。
我希望这能解释 CollectionProxy
class 为何如此有用
我想知道 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 []>
我不知道它们之间有什么区别,为什么要这样实现?
好的。区别很简单。
根据您的示例进行解释:
v.wheels
中的关联代理有:
v
中的对象作为@owner;- 它的轮子集合为@target;
- @reflection 对象表示一个
:has_many
宏。
来自docs:
Association proxies in Active Record are middlemen between the @owner and the @target. The @target object is not loaded until needed.
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 []>
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
、reflection
和target
所有者
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
您还可以访问另外两个方法 reset
和 reload
,第一个 (reset
) 清除缓存的关联对象,第二个 (reload
) 更常见,用于 reset
然后从数据库中加载关联对象。
我希望这能解释 CollectionProxy
class 为何如此有用