我要更新@some_instance,除非用户不符合某些条件。我把条件检查和@ some_instance.save放了!在事务块中,这样如果它们中的任何一个失败,都不会进行任何事务。这很好,但是我在返回正确的错误消息时遇到了麻烦。如果用户不符合条件,我想返回原因,或者如果@some_instance不保存,我想返回该错误。

我的代码:

#some_controller.rb
begin
  Some_Class.transaction do
    return render json: { error: @user.errors }, status: :payment_required,
      location: new_payment_path unless @user.meets_criteria
    @some_instance.save!
  end
rescue ActiveRecord::RecordInvalid => exception
  render :json => { :error => exception.messages }, status: :unprocessable_entity
rescue => error
  # handle some other exception
end

#User.rb
def meets_criteria
  self.errors[:base] << "Does not meet criteria"
  return false
end


我面临的问题是:当mets_criteria方法返回false时,我希望执行return render json行。而是在“ rescue => error”中捕获错误。

返回render json永远不会执行。

更新:

@Gen建议在事务do块中使用before_action而不是调用Meets_criteria。我认为这是一个更好的实现,但是我仍然很好奇为什么从未调用过返回渲染。是因为ActiveRecord引发错误?如果是这样,那该不应该被RecordInvalid异常捕获吗?

最佳答案

@TheJKFever,我不确定您的代码是否应该跳转到任何救援块(嗯,我实际上通过运行它进行了确认)。

您的some_validation方法返回false,因此“除非@ user.some_validation”评估为true,并且使用以下日志输出执行渲染:

Completed 402 Payment Required in 128ms

{"error":{"base":["Some error message"]}}


您可以参考ActiveRecord::RecordInvalid API以获得有关RecordInvalid的详细信息。即,“在记录无效时通过保存引发并创建!”。

因此,您的“拯救ActiveRecord :: RecordInvalid =>异常”应该可以处理“ @ some_instance.save!”中的异常!语句,而不是在您的自定义验证中。

在您的验证中,您实际上没有引发ActiveRecord :: RecordInvalid异常的代码,并且可能因另一个错误而失败,可以通过将其详细输出来轻松检查。

为了正确地使用some_validation和“ self.errors [:base] <
验证:some_validation

在这种情况下,如果您致电“ @ user.save!”而不是“ @ some_instance.save!”,您将陷入该“救援ActiveRecord :: RecordInvalid =>异常”块中。

PS:@TheJKFever,我在下面看到了您的评论之一,并想澄清一些事情。验证具有明确定义的目的,可以在保存之前验证模型,因此您所需要的不是模型验证。您真正需要的是控制器上的before_action,它将检查您的用户已准备好用于此类操作(将其视为控制器验证)。是的,您可能需要在用户模型上使用某种方法来进行检查。

更新(问题更新后)

正如我前面提到的,@ TheJKFever在实现您的代码时能够执行“ return render json:{error:@ user.errors} ...”。因此,如果它对您失败,则一定是由于在Meets_criteria调用期间发生了某些异常,但它不是RecordInvalid异常。由于您将mets_criteria包装到事务中,因此,如果@ some_instance.save,它可能会进行一些数据库更改以回滚!不成功。最好也将您的mets_criteria包裹在相同的救援块中并找出答案。你创造!或保存!在满足条件中有东西吗?如果是这样,那么它也可能引发RecordInvalid异常。问题在于,在您的代码中,Meets_criteria和@ some_instance.save!可以引发RecordInvalid,并且无法在代码中看到哪一个。在任何情况下,如果您将急救包都包含在Meets_criteria中,则可以从中发送渲染错误请求。而且,如果您决定使用before_action过滤器,则必须将整个事务移入其中(假设它需要数据的完整性)。

关键是,仅在保存时才抛出ActiveRecord :: RecordInvalid异常!或创建!因无效数据而失败。在您的代码中可能不是这种情况,并且引发了一些其他异常,并且最终导致“ rescue => error”块。

08-07 18:33