如何在ActiveRecord事务中获得保存(无感叹号)语义?

时间:2010-03-20 03:36:15

标签: ruby-on-rails database activerecord transactions

我有两个模型:PersonAddress我想在交易中创建。也就是说,我想尝试创建Person,如果成功,则创建相关的Address。我想使用save语义(返回truefalse)而不是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

我想我的第一个问题是:为什么不是这个交易块......在两次保存中进行交易?

2 个答案:

答案 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模块。