has_many 关联上的 find_or_initialize_by 导致重复错误

发布于 2024-12-26 01:01:58 字数 1105 浏览 4 评论 0原文

自从我从 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!

最终会尝试将相同的记录插入到收藏夹表中。 (请注意,在此示例中,(user_id, site_id) 对在收藏夹中必须是唯一的)

有趣的是,如果我使用 find_or_create 而不是 find_or_initialize ,则不会引发异常。

在堆栈跟踪中,我注意到 autosave_association 被调用,不知道为什么,但实际上 has_many :favorites, :autosave => false 而不是 has_many :favorites 也可以消除错误。由于我从来不关心 autosave,我什至不确定 :autosave => false 是否是一个好主意。

我做错了什么,还是 Rails 的错误?有谁可以指点我看一下吗?

I'm seeing a strange error since I moved from Rails 3.0.11 to 3.1.3. Here's a standalone code to reproduce the error:

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!

will end up ActiveRecord::RecordNotUnique attempting to INSERT the same record to the favorites table. (Note that with this example, (user_id, site_id) pair must be unique on favorites)

Interestingly, if I use find_or_create instead of find_or_initialize no exceptions are raised.

In the stack trace I noticed autosave_association gets called, don't know why, but actually has_many :favorites, :autosave => false instead of has_many :favorites removes the error, too. As I've never cared about autosave, I'm not even sure if :autosave => false is a good idea or not.

What am I doing wrong, or is it a Rails bug? Can anyone give me a pointer to look at?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

风吹雨成花 2025-01-02 01:01:58

您是否尝试过不调用 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/导轨/导轨/拉/3610

have you tried not calling f.save! ? u.save! should save both favourites and users.

> 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

I think what you find is that the new favourite f you have created is a separate object. Hence you will be saving f, while there is another un-saved favourite too in u.favourites. Hence a non-unique error occurs when you save u (which also saves the favourites)

I'm not sure if this is a bug newly introduced in Rails 3.1. It may be intentional.

In Rails 3.0 find_or_initialize_by did not populate the array

> f = u.favorites.find_or_initialize_by_site_id(123)

> u.favorites
==> []

Looks like a bug - see https://github.com/rails/rails/pull/3610

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文