您好我最近在尝试执行以下操作时遇到了这个问题:
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的引擎盖上看会有所帮助。我不确定,这就是我猜的原因。
这只是一个好奇的事情。任何帮助/指导表示赞赏
答案 0 :(得分:2)
你想:
posts.detect {|p| p.id == 123}
find
是detect
的别名,但它会被您从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