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

Jam*_*sen 3 database activerecord transactions ruby-on-rails

我有两个型号:PersonAddress我想在一个事务中创建.也就是说,我想尝试创建Person,如果成功,则创建相关的Address.我想使用save语义(return 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
Run Code Online (Sandbox Code Playgroud)

(将self.save调用更改为if self.save围绕其余部分的块也无济于事,因为Person即使Address失败,保存仍然会成功.)

这不起作用,因为它ActiveRecord::StatementInvalidtransaction块中引发异常而不触发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
Run Code Online (Sandbox Code Playgroud)

Rails文档明确警告说,不要捕捉ActiveRecord::StatementInvalid里面transaction块.

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

Har*_*tty 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
Run Code Online (Sandbox Code Playgroud)

我不喜欢TX的实现方式.但这就是你如何解决这些问题.