find_or_initialize_by on has_many关联会导致重复错误

时间:2012-01-10 04:26:44

标签: ruby-on-rails activerecord ruby-on-rails-3.1 associations autosave

自从我从Rails 3.0.11迁移到3.1.3后,我发现了一个奇怪的错误。这是一个重现错误的独立代码:

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错误?任何人都可以给我一个指针来看看吗?

1 个答案:

答案 0 :(得分: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中还有另一个未保存的收藏夹。因此,当您保存u(也保存收藏夹)时会发生非唯一错误

我不确定这是否是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