【问题标题】:How can I re-raise a Ruby exception in a Rails rescue_from statement?如何在 Rails rescue_from 语句中重新引发 Ruby 异常?
【发布时间】:2016-05-18 03:22:43
【问题描述】:

我的 Rails 4 应用程序使用 RocketPants 作为其 JSON API,使用 Pundit 进行授权。

我的 /app/controllers/api/v1/base_controller.rb 文件中有用于处理 Pundit 错误的代码。每当用户无权更新资源时,Pundit 都会抛出 NotAuthorizedError 异常,我使用 user_not_authorized 方法将其救出:

class API::V1::BaseController < RocketPants::Base
  include Pundit
  version 1

  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

  def user_not_authorized
    error! :forbidden
  end

end

当我从异常处理程序调用RocketPants provideserror! 方法时,我希望得到这样的JSON 响应:

{
  "error":             "forbidden",
  "error_description": "The requested action was forbidden."
}

然而,调用error! 会立即破坏请求:

Completed 500 Internal Server Error in 143ms

RocketPants::Forbidden - RocketPants::Forbidden:
  rocket_pants (1.13.1) lib/rocket_pants/controller/error_handling.rb:44:in `error!'
  app/controllers/api/v1/base_controller.rb:61:in `user_not_authorized'

完整的堆栈跟踪here

为什么在我的 Pundit 异常处理程序中调用 error! 方法时没有做它应该做的事情?

如果我将error! :forbidden 放在控制器操作的中间,它会按预期工作。

对于上下文,从 base_controller.rb 继承并调用 Pundit 的 authorize 方法的控制器如下所示:

class API::V1::MealsController < API::V1::BaseController

  before_filter :find_entity

  def create
    meal = @entity.meals.build(meal_params)

    authorize(@entity, :update?)

    if meal.save
      expose meal, status: :created
    else
      expose meal.errors, status: 422
    end
  end

end

【问题讨论】:

    标签: ruby-on-rails pundit rescue rocketpants


    【解决方案1】:

    显然在rescue_from 中引发异常是一个坏主意,根据 Rails 文档,处理程序中引发的异常不会冒泡:

    在异常处理程序中引发的异常不会向上传播。

    文档:http://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html

    我只是自己创建并返回 JSON 错误消息,而不是重新引发 RocketPants 的异常:

      def user_not_authorized
        # error! :forbidden
        head 403
        error = { error: 'Action not allowed.', error_description: 'Sorry, you are not allowed to perform this action.'}
        expose error
      end
    

    这行得通!

    更新

    我后来找到了一个更简洁的解决方案:只需将 Pundit 异常映射到 RocketPants 异常。这意味着无论何时引发 Pundit::NotAuthorizedError 错误,它都会被视为 RocketPants::Forbidden 错误。

    将整个解决方案简化为base_controller.rb 顶部的一行代码:

      map_error! Pundit::NotAuthorizedError, RocketPants::Forbidden
    

    不需要处理程序。

    【讨论】:

      猜你喜欢
      • 2012-01-13
      • 1970-01-01
      • 2013-10-19
      • 1970-01-01
      • 2014-07-09
      • 2018-12-21
      • 2012-01-24
      • 1970-01-01
      • 2016-08-18
      相关资源
      最近更新 更多