我正在尝试使用事务支持创建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关系有关吗?
答案 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!()方法可以。