Transactions in a Rake task
I am trying to create a rake task with transaction support. There is a has_one relationship between User->Profile and User->Location.
The following code should fail, as there is already a User with the username of 'foo':
ActiveRecord::Base.transaction do
begin
u = User.create!(:username => 'foo', :email_address => 'foo@bar.com')
p = Profile.create!(:first_name => 'foo', :last_name => 'bar')
u.profile=p
l = Location.create!(:address => "chanhassen,MN")
u.location=l
rescue Exception => e
rollback()
puts "error: #{e}"
end
end # transaction
Unfortunately, the error message (about the duplicate entry) isn't raised, and the Profile and Location models a开发者_Go百科re created, but not assigned to the User. What am I not understanding?
--edit--
I used the create!() method instead of the create() method. This succeeds in raising the duplicate username error. However, if the User validation passes, but the Profile validation fails (e.g. the last_name field is missing), the User is still created in the DB. This should cause the transaction to fail (it does) and rollback the User (it doesn't).
Another question: the User.create doesn't generate an id:
#<User id: nil, username: "foo">
while the Profile.create and Location.create do:
#<Location id: 1, locatable_id: nil, locatable_type: nil>
#<Profile id: 1, user_id: nil, first_name: "foo", last_name: "bar">
Seems like all three models should wait to create their primary key until all of the validations have succeeded. Is this related to the has_one relationship?
Try using create!
method instead of create
(as in User.create! :username => 'foo'
). create
doesn't raise an exception on error, create!
does that.
This has the desired behavior:
ActiveRecord::Base.transaction do
begin
u = User.new(:username => 'foo', :email_address => 'foo@bar.com')
l = Location.new(:address => "Chanhassen, MN")
u.location=l
p = Profile.new(:first_name => 'Foo', :last_name => 'Bar')
u.profile=p
u.save!
rescue Exception => e
ActiveRecord::Rollback
puts e
end
end # transaction
The new() method doesn't (it seems) trigger validation. The save!() method does.
精彩评论