使用ActiveRecord冒泡嵌套事务失败

时间:2014-01-04 21:18:45

标签: ruby-on-rails activerecord

我在服务对象中有一个方法,它组成应该包含在事务中的操作。其中一些操作也包含在事务中。例如:

class PostCreator
   def create
      ActiveRecord::Base.transaction do
        post.do_this
        post.do_that
        user.do_more(post, other_stuff)
      end
   end
 end

 def Post
   def do_this
     transaction do; ...; end
   end
 end

我需要任何嵌套的失败,一直到顶部,但我不知道如何实现这一点,nested transactions上的ActiveRecord文档似乎没有提供解决方案。来自文档:

# Standard nesting

User.transaction do
  User.create(username: 'Kotori')
  User.transaction do
    User.create(username: 'Nemu')
    raise ActiveRecord::Rollback    #  This won't bubble up:
                                    #  _Both_ users will still be created.
  end
end

# Nesting with `requires_new: true` on the nested transaction

User.transaction do
  User.create(username: 'Kotori')
  User.transaction(requires_new: true) do
    User.create(username: 'Nemu')
    raise ActiveRecord::Rollback    #  This won't bubble up either
                                    #  "Kotori" will still be created.
  end
end

3 个答案:

答案 0 :(得分:28)

以下是您在嵌套交易中出现失败的方法:

User.transaction do
  User.create(username: 'Kotori')
  raise ActiveRecord::Rollback unless User.transaction(requires_new: true) do
    User.create(username: 'Nemu')
    raise ActiveRecord::Rollback
  end
end

基本上,您必须在顶级事务中引发错误,以便进行回滚。为此,如果嵌套事务返回falsey值(nil)或truthy值,则引发错误。

希望有所帮助!

答案 1 :(得分:12)

另一种更简单的方法,你可以引发一个CustomError< StandardError的。与ActiveRecord :: Rollback不同,Error将通过父事务冒泡。您可以在任何需要的地方处理它。所有其他内部交易将被回滚。

尝试以下模板。

ActiveRecord::Base.transacton do
    ActiveRecord::Base.transacton do
        raise StandardError.new
    end
end

答案 2 :(得分:0)

在嵌套事务的情况下,抛出自定义错误始终是一个不错的选择。请在nested-transations-in-rails上找到更多详细信息。