繁体   English   中英

捕获错误时不会在 Rails 事务中触发回滚

[英]Rollback not triggering in rails transaction when catching errors

我在 controller 操作中有一些 Rails 代码,其中有一个带有自定义错误的事务。

当事务中发生特殊错误时,我希望事务回滚并呈现一些 json 代码,但是我似乎无法使事务回滚(它总是提交)然后呈现一些 json。这是我的以下代码:

  def controller_action
    error_message = nil

    begin
      ActiveRecord::Base.transaction do
        code_that_moifys_db_to_rollback
        code_that_causes_custom_error
        some_more_code_i_dont_want_to_run
      end
    rescue SomeCustomError::Error
      error_message = 'this is an error message'
      raise ActiveRecord::Rollback
    end
  rescue ActiveRecord::Rollback
    # no rollback is getting triggered and data is now corrupt if json rendered
    render :json => {error: true, message: error_message}
    # however doing "raise 'xxxxx'" will cause a DB rollback in the transaction
  end

我如何:

  • 渲染 json
  • 并强制事务回滚

我想我可能误解了回滚是如何触发的,最奇怪的是如果我在第二次救援中提出它会触发事务回滚。

我知道我来不及回答这个问题,但有些人可能仍在寻找解决方案。 因此,让我们从问题开始,然后转向解决方案。

如果您赶时间,可以直接跳到解决方案部分。

目标:

To render error response(other than saving object) and rollback transaction.

问题上下文

在 Rails 中,如果您在事务中保存了 object 错误(object.errors.present?),那么它将进入救援块(并且您可以在救援块中处理引发的异常)并且您的代码将如下所示。

def controller_action
  ActiveRecord::Base.transaction do
    if object.save!
      render_success_response('success message here')
    else
       render_error_response(object.errors)
    end
  rescue => e
    render_error_response(e)
    raise ActiveRecord::Rollback
end

我将在此处定义两种方法来呈现我将使用的错误和成功响应。

def render_error_response(errors)
  render :json => {errors: errors}
end 


def render_success_response(success_message)
  render :json => {success_message: success_message}
end 

现在在上面的代码中,你必须手动回滚事务,但是如果你想让 Rails 为你回滚事务,那么你可以像这样编写上面的代码

def controller_action
  begin
    ActiveRecord::Base.transaction do
      if object.save!
        render_success_response('success message here')
      else
         render_error_response(object.errors)
      end
    rescue => e
      render_error_response(e)
   end
 end

在上面的代码中,rails 会自动为你回滚事务,并会以异常错误进入救援块。

问题

但是,如果您有一个错误数组来响应(调用)服务或其他内容,并且如果该数组中存在错误您想要呈现这些错误并回滚事务怎么办? (如您所知,这次 Rails 不会为您回滚事务,因为这些错误不会保存 object 错误)

Rails 7 以下版本的解决方案

def controller_action
  begin
    ActiveRecord::Base.transaction do
      response = ResponseFromService
      if response[:errors].blank?
        render_success_response('success message here')
      else
         render_error_response(response[:errors])
         raise ActiveRecord::Rollback
      end
    rescue => e
      render_error_response(e)
   end
 end

Rails 7 的解决方案

在 rails 7 中,我们得到了一个新特性,它正是针对这个问题的,它使用return关键字,所以在 rails 7 中,代码看起来像这样

def controller_action
  begin
    ActiveRecord::Base.transaction do
      response = ResponseFromService
      if response[:errors].blank?
        render_success_response('success message here')
      else
         return render_error_response(response[:errors])
      end
    rescue => e
      render_error_response(e)
   end
 end

警告:请注意,return 关键字将静默(不引发异常)回滚事务,因此在使用它时要小心。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM