ActiveRecord关系和对象模型

时间:2011-04-11 21:10:54

标签: ruby-on-rails ruby activerecord

您好我最近在尝试执行以下操作时遇到了这个问题:

posts = User.first.posts
posts.find {|p| "p.id" == 123} => ActiveRecord::RecordNotFound: Couldn't find Post without an ID

那是试图调用ActiveRecord查找。它期待:

posts.find(123)

但我不想再次查询数据库。所以我需要这样做:

posts.to_a.find {|p| "p.id" == 123}

根据posts.class,我虽然在处理数组。为什么我要打电话给它_a?

posts.class => Array
posts.superclass => ActiveRecord::Base

为什么我可以在帖子上调用超类,如果它(可能)是一个Array的实例,为什么它会返回ActiveRecord :: Base?

此外:

posts.ancestors.include? ActiveRecord::Base => false

如果ActiveRecord :: Base是posts数组的超类,为什么会这样?

还有一个。如果我这样做:

posts.instance_methods(false)

它返回关系类的实例方法,即Post。这似乎很奇怪,因为posts是一个数组。同样,如果我创建一个“常规”数组:

a = [1, 2]
a.instance_methods(false) => NoMethodError: undefined method `instance_methods' for [1, 2]:Array

因此,通过ActiveRecord关系查询返回的数组有点像数组但不是......它似乎继承自ActiveRecord,但它不是......或者其他东西。正当我认为我已经掌握了Ruby对象模型的时候:)也许在ActiveRecord的引擎盖上看会有所帮助。我不确定,这就是我猜的原因。

这只是一个好奇的事情。任何帮助/指导表示赞赏

4 个答案:

答案 0 :(得分:2)

你想:

posts.detect {|p| p.id == 123}

finddetect的别名,但它会被您从find返回的ActiveRecord集合代理上的posts方法隐藏。

答案 1 :(得分:0)

find方法仅在ActiveRecord :: Base类上可用。它是一个类方法,而不是实例方法。

是的,这不完全是一个数组,但它的行为就像一个Enumerable。

在这种情况下,您可以使用选择

posts.select{|p| p.id == 123}.first

我在最后添加了.first,因为select会返回另一个数组,只需要一个元素。

希望这有帮助。

答案 2 :(得分:0)

看起来ActiveRecord::Base会覆盖Enumerable所需的#find方法。这就是您需要将其转换为没有覆盖查找方法的数组的原因。

答案 3 :(得分:0)

posts.ancestors.include? ActiveRecord::Base => false

是假的,因为posts是Post对象的集合,而不是ActiveRecord::Base的后代。 posts集合中的任何单个项目都是ActiveRecord::Base

的后代