5

我看到一個奇怪的錯誤,因爲我從Rails 3.0.11移動到3.1.3。這裏有一個獨立的代碼重現錯誤:find_or_initialize_by has_many關聯導致重複錯誤

require 'active_record' 

ActiveRecord::Base.establish_connection(
    :adapter => 'mysql2', 
    :username => 'root', 
    :database => "some_development" 
) 

class User < ActiveRecord::Base 
    has_many :favorites 
end 

class Favorite < ActiveRecord::Base 
    belongs_to :user 
end 

u = User.create 

# f = u.favorites.find_or_create_by_site_id(123)  #=> pass 
f = u.favorites.find_or_initialize_by_site_id(123) #=> fail 
f.some_attr = 'foo' 
f.save! 

u.name = 'bar' 
u.save!    # ActiveRecord::RecordNotUnique will be thrown here! 

將結束ActiveRecord::RecordNotUnique試圖INSERT同一記錄到favorites表。 (請注意,對於此示例,(user_id,site_id)對在收藏夾上必須唯一)

有趣的是,如果我使用find_or_create而不是find_or_initialize,則不會引發異常。

在堆棧跟蹤我注意到autosave_association被調用,不知道爲什麼,但實際上has_many :favorites, :autosave => false代替has_many :favorites刪除錯誤了。因爲我從來不在乎autosave,我甚至不確定:autosave => false是不是一個好主意。

我在做什麼錯,或者它是一個Rails錯誤?任何人都可以給我一個指針來看看?

+0

是否User模型有一個字段的唯一性驗證?此外,它旁邊還有'#=> pass'註釋嗎?你是否試圖一次創建兩個版本的收藏或什麼? – Batkins 2012-01-10 04:39:27

+0

是的,用戶模型有一些驗證,包括唯一性,但我不確定它是如何關聯的。如果你註釋了find_or_create而不是find_or_initialize,它應該沒有錯誤地傳遞,正如我的問題所述。 – kenn 2012-01-10 21:59:23

+0

你可以試試這個:而不是'u.save!',做'u.save'然後'放置u.errors'或'p u.errors'。什麼是錯誤。我有一種感覺,這是一個問題,你創建的用戶不能通過唯一性驗證(因爲你正在使用一個通用的'User.create'而沒有提供屬性)。 – Batkins 2012-01-11 16:26:33

回答

5

你有沒有試過不打f.save!u.save!應保存收藏夾和用戶。

> f = u.favorites.find_or_initialize_by_site_id(123) 

> u.favorites.include?(f) 
==> false 

> f2 = u.favorites.build(:site_id => 123) 

> u.favorites.include?(f2) 
==> true 

我想你會發現什麼是您所創建的新寵f是一個單獨的對象。因此,您將保存f,而在u.favourites中還有另一個未保存的收藏夾。因此,當你保存你的時候會發生一個非唯一的錯誤(這也保存了我的最愛)

我不確定這是否是Rails 3.1中新引入的錯誤。這可能是故意的。

在Rails 3.0 find_or_initialize_by,沒有填充陣列

> f = u.favorites.find_or_initialize_by_site_id(123) 

> u.favorites 
==> [] 

看起來像一個錯誤 - 見https://github.com/rails/rails/pull/3610

+0

它必須在那裏,因爲'u.save!'在'f.save!'的代碼中很遙遠,有可能'u'沒有被弄髒並跳過保存。我想知道它爲什麼會引發錯誤。 – kenn 2012-01-10 22:05:19