2011-04-11 115 views
1

嗨努力做到以下几点,当我最近就遇到了这个: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。为什么我必须打电话给to_a?

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

为什么我可以调用父类的职位,如果是(大概)阵列的一个实例,为什么它返回的ActiveRecord :: Base的?

另外:

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

为什么是假的,如果的ActiveRecord :: Base的是职位阵列的超?

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

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中引入一些底层的看法会有所帮助。我不确定,这就是为什么我问我猜。

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

+1

为什么要在块中将字符串与int进行比较?你为什么要做'posts.find {| p | “p.id”== 123}'而不是'p.id'? – Geo 2011-04-11 22:35:52

+0

是的,这是一个错字。谢谢指出 – jgoggles 2011-04-11 22:54:59

回答

0

查找方法只适用于ActiveRecord :: Base类。它是一个类方法,而不是一个实例方法。

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

在这种情况下,你可以在最后使用select

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

我加了。首先,因为选择将返回另一个数组,只有一个元素吧。

希望这会有所帮助。

+1

正确的方法是在这里使用'detect'而不是'select',因为'detect'会返回遇到的第一个元素并停止查找。只是一个有用的供参考。 – 2011-04-11 22:49:29

0

它看起来像ActiveRecord::Base覆盖Enumerable所需的#find方法。这就是为什么你需要将它转换为一个没有覆盖find方法的数组。

2

你想:

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

finddetect的别名,但它是由你得到posts回来ActiveRecord的收集代理find方法阴影。

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

是错误的,因为posts是Post对象的集合,而不是ActiveRecord::Base的后裔。文章集合中的任何单个项目都将是ActiveRecord::Base的后裔