我有一个Account
模型。它具有通常的validations
和after_save
回调。有一个要求,并且将根据某些其他验证策略来创建帐户对象。我有以下代码片段,效果很好:
def special_account_creation
Account.transaction do
a = Account.create(params)
resp = update_third_party(a) # Throws exception if unable to update
validate_amount(a, resp) # Throws exception if `a` is invalid
# rescue Rollback ??? <--- How to do this
# msg = <transaction_error_details>
# Rails.logger.info("Special Account not created due to: #{msg}")
end
end
a
帐户在调用第三方API或验证过程中发生任何错误时被销毁。
我想知道如何记录错误以了解为何回滚该事务。
答案 0 :(得分:0)
ActiveRecord
不会在更新失败和/或验证失败时引发Rollback
。
您应该挽救筹集的资金,然后有两个机会:筹集Rollback
仅回滚事务并继续正常的执行流程,或者重新筹集的资金确实破坏了正常的流程。
def special_account_creation
Account.transaction do
a = Account.create(params)
begin
resp = update_third_party(a) # Throws exception if unable to update
validate_amount(a, resp) # Throws exception if `a` is invalid
rescue => e # might be more specific
Rails.logger.info("Transaction failed with a message #{e.message}")
raise ActiveRecord::Rollback, e.message # just to rollback
# raise e # for re-raising the exception
end
end
end
答案 1 :(得分:0)
ActiveRecord
事务捕获内部引发的任何异常并回滚该事务。之后,如果异常为ActiveRecord::Rollback
,则该异常被抑制,否则在调用堆栈上方引发任何其他异常。
参考:https://api.rubyonrails.org/classes/ActiveRecord/Rollback.html
因此您可以执行以下操作:
Account.transaction do
begin
a = Account.create(params)
resp = update_third_party(a) # Throws exception if unable to update
validate_amount(a, resp) # Throws exception if `a` is invalid
rescue StandardError => e # <- assuming all errors need to be logged
Rails.logger.info("Special Account not created due to: #{msg}")
raise e # <-- Don't forget to raise the error!
end
end
我建议从救援块中引发错误-这将回滚事务,并且如果错误不是ActiveRecord::Rollback
之外的其他错误,它将在事务块之外引发。您可以在基本控制器的rescue_from block中处理这些错误。
也更喜欢捕获StandardError
而不是Exception
:https://robots.thoughtbot.com/rescue-standarderror-not-exception
我假设我们想捕获该块中所有可能的错误,因此使用StandardError
,否则使用需要拦截的任何特定错误。