开发者

Transactions in a Rake task

开发者 https://www.devze.com 2023-02-12 05:10 出处:网络
I am trying to create a rake task with transaction support.There is a has_one relationship between User->Profile and User->Location.

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消