2011-10-24 36 views
0

我是新來的rails(和一般編碼),並且正在編寫一個使用RSpec進行測試的小項目。我目前被困在一個模型測試中,該測試應該非常簡單,我正在撕掉我的頭髮。find_or_create_by_name_and_location在Rails中創建ActiveRecord副本

我有一個日誌文件來解析錯誤。每個錯誤都有一個名稱(例如NoMethodError)和一個位置(例如"app/controllers/public/profiles_controller.rb:46:in 'index')。我已經從日誌中成功解析了它們,現在正在嘗試使用ActiveRecord將它們寫入我的數據庫Errors

我希望每個錯誤/位置組合只能記錄一次。我目前正在使用該塊在我的模型可以這樣做:

#app/models/error.rb 
Error.find_or_create_by_name_and_location(@name, @location) do |error| 
error.first_seen = (Time.now - 1.day) 
error.last_seen = Time.now # These time objects are just filler for now 
end 

至於我可以做出來,這應該在我Errors數據庫只創建新條目,如果沒有預先存在的條目具有相同的名稱和位置。然而,這種情況並非如此。

我已經創建了一個樣本日誌來運行我的測試,它有兩個相同的和一個唯一的錯誤/位置對。我希望這些被記錄爲Errors中的2個條目。但是,當我運行我的測試時,重複項不會被過濾掉,所以我最終輸入了3個條目。

我寫了一個測試,以檢查find_or_create_by_name_and_location方法,它工作正常:

#RSpec 
#spec/models/error_spec.rb 
Error.find_or_create_by_name_and_location("foo", "bar") 
Error.find_or_create_by_name_and_location("foo", "bar") 
Error.should have(1).record 
#Test passes 

我用盡了一切我能想到的,但我發現無處可去快的,所以任何幫助將是非常讚賞!

回答

1

無論find_or_create_by方法是否按預期工作,您應該向模型添加驗證以強制實施唯一性。

class Error << ActiveRecord::Base 

    validates_uniqueness_of :name, :scope => :location 

end 

這樣,只能有一個記錄具有相同的名稱和位置。

+0

好啊,這真的很有用,謝謝 - 我應該能夠使用它作爲解決方法。仍然希望我知道爲什麼'find_or_create_by'沒有像我期望的那樣工作......即使是我的老闆也無法解決這個問題,所以我不認爲這只是我的總新手! – omnikron

+0

好吧,現在我完全被絆倒了 - 它_still_不起作用。即使使用如上所述的模型強制唯一性,我最終會得到兩個重複條目。 find_or_create_by代碼在'if'循環中,我無法想象競爭條件起作用(即代碼首先驗證這兩個錯誤的唯一性,然後_then_寫入)。任何想法呢? – omnikron

+1

後來我遇到了類似的問題。解決辦法是把它寫成兩個查詢'除非instance = Model.find(); instance = Model.create(); end'。不是很漂亮,但有效。 –