2011-04-11 64 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的後裔