我有两个模型:Person
和Address
我想在交易中创建。也就是说,我想尝试创建Person
,如果成功,则创建相关的Address
。我想使用save
语义(返回true
或false
)而不是save!
语义(提升ActiveRecord::StatementInvalid
或不提高)。
这不起作用,因为user.save
不会触发事务回滚:
class Person
def save_with_address(address_options = {})
transaction do
self.save
address = Address.build(address_options)
address.person = self
address.save
end
end
end
(将self.save
调用if self.save
块更改为其余部分无效,因为即使Person
失败,Address
保存仍然成功。)
这不起作用,因为它会在ActiveRecord::StatementInvalid
块中引发transaction
异常,而不会触发ActiveRecord::Rollback
:
class Person
def save_with_address(address_options = {})
transaction do
save!
address = Address.build(address_options)
address.person = self
address.save!
end
end
end
Rails documentation特别警告不要在ActiveRecord::StatementInvalid
区块内抓取transaction
。
我想我的第一个问题是:为什么不是这个交易块......在两次保存中进行交易?
答案 0 :(得分:5)
这个怎么样?
class Person
def save_with_address(address_options = {})
tx_error = false
transaction do
begin
self.save!
address = Address.build(address_options)
address.person = self
address.save!
rescue Exception => e
# add relevant error message to self using errors.add_to_base
raise ActiveRecord::Rollback
tx_error = true
end
end
return true unless tx_error
# now roll back the Person TX.
raise ActiveRecord::Rollback
return false
end
end
我不喜欢TX的实现方式。但这就是解决问题的方法。
答案 1 :(得分:0)
告诉ActiveRecord为您执行此操作。为您节省大量问题:
class Person < ActiveRecord::Base
belongs_to :address, :autosave => true
end
好消息是,Person的错误将包含地址'验证错误,格式正确。
有关详细信息,请参阅AutosaveAssocation模块。