【问题标题】:find_or_initialize_by on has_many association causes duplicate errorfind_or_initialize_by on has_many 关联导致重复错误
【发布时间】:2012-01-10 04:26:44
【问题描述】:

自从我从 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 =&gt; false 而不是has_many :favorites 也消除了错误。因为我从不关心autosave,所以我什至不确定:autosave =&gt; false 是否是个好主意。

我做错了什么,还是 Rails 错误?谁能给我指点看看?

【问题讨论】:

  • 用户模型是否对字段的唯一性进行了验证?另外,旁边带有#=&gt; pass 的注释是什么?您是想同时创建两个版本的收藏夹吗?
  • 是的,用户模型有很多验证,包括唯一性,但我不确定它是如何关联的。如果您在 find_or_create 行而不是 find_or_initialize 中添加注释,它应该会通过而不会出现错误,如我的问题中所述。
  • 你能试试这个吗:不是u.save!,而是u.save,然后puts u.errorsp u.errors。有什么错误。我有一种感觉,这是一个问题,您正在创建一个没有通过唯一性验证的用户(因为您使用的是通用 User.create 而没有输入任何属性)。
  • 实际上u.save 也引发了同样的异常。也就是说,它无法到达以下puts u.errors。因为它是数据库级别的唯一约束,而不是 ruby​​ 级别的验证。

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


【解决方案1】:

你试过不打电话给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

【讨论】:

  • 它必须在那里,因为u.save! 在代码中与f.save! 相距较远,并且u 有可能没有被弄脏并跳过保存。我想知道它引发错误的原因。
猜你喜欢
  • 2018-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-27
  • 1970-01-01
  • 2011-04-21
相关资源
最近更新 更多