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