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?
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