Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
ActiveRecord中集合的Ruby类型_Ruby_Activerecord - Fatal编程技术网

ActiveRecord中集合的Ruby类型

ActiveRecord中集合的Ruby类型,ruby,activerecord,Ruby,Activerecord,如果我在ActiveRecord中有一个包含子对象集合的对象,即 class Foo < ActiveRecord::Base has_many :bars, ... end 我收到: ActiveRecord::RecordNotFound: Couldn't find Bar without an ID 我认为这是因为ActiveRecord为了自己的目的劫持了find方法。现在,我可以使用检测,一切都很好。然而,为了满足我自己的好奇心,我尝试使用元编程显式地将find方法偷回

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

class Foo < ActiveRecord::Base
  has_many :bars, ...
end
我收到:

ActiveRecord::RecordNotFound: Couldn't find Bar without an ID
我认为这是因为ActiveRecord为了自己的目的劫持了
find
方法。现在,我可以使用
检测
,一切都很好。然而,为了满足我自己的好奇心,我尝试使用元编程显式地将
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.bar
是一个数组,但:

foo_instance.bars.instance_of?(Array) -> true
有谁能帮我解释一下这一点,以及用元编程绕过它的方法吗

我想这是因为ActiveRecord 劫持了find方法以获取其 自己的目的

这不是真正的解释
foo_instance.bar
不返回数组的实例,而是返回
ActiveRecord::Associations::AssociationProxy
的实例。这是一个特殊的类,用于充当持有关联的对象和关联对象之间的代理

AssociationProxy对象充当数组,但它实际上不是数组。以下详细信息直接取自文档

# 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.

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

ActiveRecord关联实际上是反射实例,它覆盖了的实例?和相关的方法来隐瞒它是什么类。这就是为什么您可以做一些事情,比如添加命名作用域(比如“最近”),然后调用foo_instance.bar.recent。如果“条”是一个数组,这将是相当棘手的


尝试签出源代码(“locate reflections.rb”应该可以在任何unix对话框中找到它)。查德·福勒(Chad Fowler)在这个话题上做了一次内容丰富的演讲,但我似乎在网上找不到任何链接。(有人想编辑这篇文章来包含一些吗?

正如其他人所说,关联对象实际上不是数组。要找出真正的类,请在irb中执行以下操作:

class << foo_instance.bars
  self
end
# => #<Class:#<ActiveRecord::Associations::HasManyAssociation:0x1704684>>

ActiveRecord::Associations::HasManyAssociation.ancestors
# => [ActiveRecord::Associations::HasManyAssociation, ActiveRecord::Associations::AssociationCollection, ActiveRecord::Associations::AssociationProxy, Object, Kernel]
类#
ActiveRecord::Associations::HasManyAssociation.Founders
#=>[ActiveRecord::Associations::HasManyAssociation,ActiveRecord::Associations::AssociationCollection,ActiveRecord::Associations::AssociationProxy,对象,内核]
要摆脱在执行foo_instance.bar.find()时调用的ActiveRecord::Bse#find方法,以下内容将有所帮助:

class << foo_instance.bars
  undef find
end
foo_instance.bars.find {...} # Array#find is now called

class这里要澄清的是,.all方法实际上检索所有关联的模型,这些模型可能会对内存产生巨大影响,具体取决于关联的类型。例如,如果是User has_many:posts,您可能正在检索用户的整个发布历史记录,这可能是大量数据。在可能的情况下,尝试构造一个带有条件或命名作用域的find调用,以获得更好的性能。
class << foo_instance.bars
  self
end
# => #<Class:#<ActiveRecord::Associations::HasManyAssociation:0x1704684>>

ActiveRecord::Associations::HasManyAssociation.ancestors
# => [ActiveRecord::Associations::HasManyAssociation, ActiveRecord::Associations::AssociationCollection, ActiveRecord::Associations::AssociationProxy, Object, Kernel]
class << foo_instance.bars
  undef find
end
foo_instance.bars.find {...} # Array#find is now called