Подтвердить что ты не робот

Bubbling Up Nested-transaction Failures с 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

Мне нужно, чтобы все вложенные отказы всплывали до самого верха, но я не уверен, как это сделать, и ActiveRecord docs на вложенных транзакциях похоже, не предлагают решения. Из документов:

# 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
4b9b3361

Ответ 1

Здесь вы можете получить ошибки в своих вложенных транзакциях:

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

В принципе, вы должны поднять ошибку в транзакции на верхнем уровне, чтобы она тоже откатилась. Для этого вы вызываете ошибку, если вложенная транзакция возвращает значение false (nil) или правное значение.

Надеюсь, что это поможет!

Ответ 2

Еще один простой подход, вы можете поднять CustomError < Стандартная ошибка. В отличие от ActiveRecord:: Rollback, ошибка будет всплывать через родительские транзакции. Вы можете обращаться с ним везде, где это необходимо. Все остальные внутренние транзакции будут отменены.

Попробуйте шаблон ниже.

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

Ответ 3

Бросок пользовательской ошибки всегда является хорошим вариантом в случае вложенных транзакций. Подробнее см. nested-transations-in-rails.