Rake任务中的事务

时间:2011-02-21 20:42:40

标签: ruby-on-rails-3 transactions rake

我正在尝试使用事务支持创建rake任务。 User-> Profile和User-> Location。之间存在has_one关系。

以下代码应该失败,因为已经存在用户名为'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

不幸的是,没有引发错误消息(关于重复条目),并且创建了配置文件和位置模型,但未分配给用户。我不明白的是什么?

- 编辑 -

我使用了create!()方法而不是create()方法。这成功地引发了重复的用户名错误。但是,如果用户验证通过,但配置文件验证失败(例如缺少last_name字段),则仍会在数据库中创建用户。这应该导致事务失败(它确实)并回滚用户(它没有)。

另一个问题:User.create不生成id:

#<User id: nil, username: "foo">

而Profile.create和Location.create执行:

#<Location id: 1, locatable_id: nil, locatable_type: nil>
#<Profile id: 1, user_id: nil, first_name: "foo", last_name: "bar">

似乎所有三个模型应该等待创建主键,直到所有验证都成功为止。这与has_one关系有关吗?

2 个答案:

答案 0 :(得分:2)

尝试使用create!方法而不是create(如User.create! :username => 'foo'中所述)。 create不会因错误而引发异常,create!会这样做。

答案 1 :(得分:2)

这具有所需的行为:

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

new()方法不会(似乎)触发验证。 save!()方法可以。

相关问题