嗨,我最近在尝试执行以下操作时遇到了这个问题:
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}
根据post.class,我以为我在处理一个数组。为什么我必须调用它上的to_a?
posts.class => Array
posts.superclass => ActiveRecord::Base
如果它(大概(是Array的实例,为什么我可以在posts上调用超类?为什么它会返回ActiveRecord::Base?
还有:
posts.ancestors.include? ActiveRecord::Base => false
如果ActiveRecord::Base是posts数组的超类,为什么会出现错误?
再来一次。如果我这样做:
posts.instance_methods(false)
它返回关系类的实例方法,即Post。这似乎很奇怪,因为帖子是一个数组。类似地,如果我创建一个"常规"数组:
a = [1, 2]
a.instance_methods(false) => NoMethodError: undefined method `instance_methods' for [1, 2]:Array
因此,通过ActiveRecord关系查询返回的数组有点像数组,但不是。。。它似乎继承了ActiveRecord,但它并没有。。。或者什么的。就在我认为我已经完全掌握了Ruby对象模型的时候:(也许深入了解一下ActiveRecord会有所帮助。我不确定,我想这就是我问的原因。
这只是一件令人好奇的事情。感谢任何帮助/指导
您想要:
posts.detect {|p| p.id == 123}
find
是detect
的别名,但它被从posts
返回的ActiveRecord集合代理上的find
方法遮蔽。
是的,这并不完全是一个数组,但它的行为确实像Enumerable。
在这种情况下,您可以使用select
posts.select{|p| p.id == 123}.first
我在末尾添加了.first,因为select将返回另一个数组,无论它只包含一个元素。
希望这能有所帮助。
看起来ActiveRecord::Base
覆盖了您想要从Enumerable中获得的#find
方法。这就是为什么您需要将它转换为一个没有覆盖find方法的数组。
posts.ancestors.include? ActiveRecord::Base => false
为false,因为posts是Post对象的集合,而不是ActiveRecord::Base
的后代。posts集合中的任何单个项目都将是ActiveRecord::Base
的后代