使用Rails中的模块执行错误处理的最佳方法?

时间:2017-09-27 18:05:18

标签: ruby-on-rails ruby error-handling api-design

我对Rails和后端API开发很新,所以如果我滥用一个概念左右,请原谅。现在,我正在尝试重构代码库周围散布的大量条件错误处理代码,并通过将其作为模块包含在API API控制器中,使用明确的已获救异常列表。这将允许我为每个捕获的异常附加自定义但任意的代码,只要我们使用bang替代方法来处理活动记录方法,并且错误处理代码可以存在于一个地方。到目前为止,对于错误处理模块,我有类似的东西:

# app/lib/error/error_handling.rb
module Error
  module ErrorHandling
    def self.included(klass)
      klass.class_eval do
        rescue_from ActiveRecord::RecordNotFound do |e|
          respond(:record_not_found, 404, e.to_s)
        end
        rescue_from ActiveRecord::ActiveRecordError do |e|
          respond(e.error, 422, e.to_s)
        end
        rescue_from ActiveController::ParameterMissing do |e|
          response(:unprocessable_entitry, 422, e.to_s)
        end
        rescue_from ActiveModel::ValidationError do |e|
          response(e.error, 422, e.to_s)
        end
        rescue_from CustomApiError do |e|
          respond(e.error, e.status, e.message.to_s)
        end
        rescue_from CanCan::AccessDenied do
          respond(:forbidden, 401, "current user isn't authorized for that")
        end
        rescue_from StandardError do |e|
          respond(:standard_error, 500, e.to_s)
        end
      end
    end

    private

    def respond(_error, _status, _message)
      render "layouts/api/errors", status: _status
    end
  end
end

layouts/api/errors是使用jbuilder构建的视图。 在ApiController我们有:

# app/controllers/api/api_controller.rb
module Api
  class ApiController < ApplicationController
    include Error::ErrorHandling

    attr_reader :active_user

    layout "api/application"

    before_action :authenticate_by_token!
    before_action :set_uuid_header

    respond_to :json
    protect_from_forgery with: :null_session
    skip_before_action :verify_authenticity_token, if: :json_request?

    private

    ...

end

不幸的是,这似乎不起作用。运行测试表明私有方法根​​本没有加载,被认为是未定义的!

更具体地说,这是发出的错误:

uninitialized constant Error::ErrorHandling::ActiveController

undefined local variable or method `active_user' for Api::FooController

其中active_user是通过名为set_active_user的方法在实例变量中设置的属性。这显然没有被召唤。

但是正在评估ErrorHandling模块。怎么会这样?我的名字空间不正确还是什么?

感谢阅读。

2 个答案:

答案 0 :(得分:1)

答案分为两部分,因为我认为存在两个不同的问题。

统一常数错误

错误

uninitialized constant Error::ErrorHandling::ActiveController

可以通过更改此

来修复
rescue_from ActiveController::ParameterMissing do |e|
  response(:unprocessable_entitry, 422, e.to_s)
end

到此:

 rescue_from ::ActiveController::ParameterMissing do |e|
   response(:unprocessable_entitry, 422, e.to_s)
 end

(在::常量前面添加ActiveController

ruby​​中的常量查找将词法嵌套考虑在内。当您在

中引用Constant时
module Error
  module ErrorHandling
  ...
  end
end
如果以前未定义常量,

ruby​​将尝试在此命名空间中查找常量。预先::将告诉ruby忽略常量查找时的嵌套。

未定义的本地方法

错误

undefined local variable or method `active_user' for Api::FooController
引发

是因为某些代码在 active_user上调用实例方法Api::FooController,而未定义它。

答案 1 :(得分:0)

我知道这是一个老问题,但是我一直在努力,但是找到了解决方法。解决以下问题:

`undefined local variable or method `active_user' for Api::FooController` 

您需要添加扩展名ActiveSupport::Concern,例如

module Error
  module ErrorHandling
    extend ActiveSupport::Concern

    # rest of your code
  end
end