gpt4 book ai didi

ActiveRecord 中的 Ruby 集合类型

转载 作者:数据小太阳 更新时间:2023-10-29 06:46:00 26 4
gpt4 key购买 nike

如果我在 ActiveRecord 中有一个包含子对象集合的对象,即

class Foo < ActiveRecord::Base
has_many :bars, ...
end

然后我尝试针对该集合运行 Array 的 find 方法:

foo_instance.bars.find { ... }

我收到:

ActiveRecord::RecordNotFound: Couldn't find Bar without an ID

我假设这是因为 ActiveRecord 出于自己的目的劫持了 find 方法。现在,我可以使用 detect 并且一切正常。然而,为了满足我自己的好奇心,我尝试使用元编程显式窃取 find 方法一次运行:

unbound_method = [].method('find').unbind
unbound_method.bind(foo_instance.bars).call { ... }

我收到这个错误:

TypeError: bind argument must be an instance of Array

很明显 Ruby 不认为 foo_instance.bars 是一个数组,但是:

foo_instance.bars.instance_of?(Array) -> true

谁能帮我解释一下这个问题以及用元编程解决这个问题的方法?

最佳答案

I assume this is because ActiveRecord has hijacked the find method for its own purposes.

这并不是真正的解释。 foo_instance.bars 不返回 Array 的实例,而是返回 ActiveRecord::Associations::AssociationProxy 的实例。这是一个特殊的类,旨在充当持有关联的对象和关联对象之间的代理。

AssociatioProxy 对象充当一个数组,但它并不是真正的数组。以下详细信息直接取自文档。

# Association proxies in Active Record are middlemen between the object that
# holds the association, known as the <tt>@owner</tt>, and the actual associated
# object, known as the <tt>@target</tt>. The kind of association any proxy is
# about is available in <tt>@reflection</tt>. That's an instance of the class
# ActiveRecord::Reflection::AssociationReflection.
#
# For example, given
#
# class Blog < ActiveRecord::Base
# has_many :posts
# end
#
# blog = Blog.find(:first)
#
# the association proxy in <tt>blog.posts</tt> has the object in +blog+ as
# <tt>@owner</tt>, the collection of its posts as <tt>@target</tt>, and
# the <tt>@reflection</tt> object represents a <tt>:has_many</tt> macro.
#
# This class has most of the basic instance methods removed, and delegates
# unknown methods to <tt>@target</tt> via <tt>method_missing</tt>. As a
# corner case, it even removes the +class+ method and that's why you get
#
# blog.posts.class # => Array
#
# though the object behind <tt>blog.posts</tt> is not an Array, but an
# ActiveRecord::Associations::HasManyAssociation.
#
# The <tt>@target</tt> object is not \loaded until needed. For example,
#
# blog.posts.count
#
# is computed directly through SQL and does not trigger by itself the
# instantiation of the actual post records.

如果你想处理结果数组,你根本不需要元编程技能。只需进行查询并确保在真正的 Array 对象上而不是在 quacks like an array 的实例上调用 find 方法。 .

foo_instance.bars.all.find { ... }

all 方法是一个 ActiveRecord 查找器方法(find(:all) 的快捷方式)。它返回一个 array 结果。然后你可以在数组实例上调用 Array#find 方法。

关于ActiveRecord 中的 Ruby 集合类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1099533/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com