【问题标题】:How can I avoid double render in this situation?在这种情况下如何避免双重渲染?
【发布时间】:2020-10-13 10:22:49
【问题描述】:

我的控制器中的这段代码有问题:

class Api::V1::BaseController < ActionController::API
  include Pundit

  after_action :verify_authorized, except: :index
  after_action :verify_policy_scoped, only: :index

  rescue_from StandardError,                with: :internal_server_error
  rescue_from Pundit::NotAuthorizedError,   with: :user_not_authorized
  rescue_from ActiveRecord::RecordNotFound, with: :not_found

  private

  def user_not_authorized(exception)
    render json: {
      error: "Unauthorized #{exception.policy.class.to_s.underscore.camelize}.#{exception.query}"
    }, status: :unauthorized
  end

  def not_found(exception)
    render json: { error: exception.message }, status: :not_found
  end

  def internal_server_error(exception)
    if Rails.env.development?
      response = { type: exception.class.to_s, message: exception.message, backtrace: exception.backtrace }
    else
      response = { error: "Internal Server Error" }
    end
    render json: response, status: :internal_server_error
  end
end

问题

rescue_from StandardError 是我所有烦恼的根源。这个控制器工作得很好,当权威错误是唯一发生的错误时,它可以从权威白名单检查中解救出来。

但是,一旦专家同时发生任何其他错误,我就会收到DoubleRenderError,因为两个救援最终都会被触发。我正在寻找一种快速调整,以避免权威人士在另一个错误已经发生时触发,或者针对此问题的替代解决方案。

是否有任何其他错误类可以用来避免过度依赖StandardError

我尝试过的事情

  • 渲染后添加返回 它不起作用。我认为救援链会干扰render :x and return 的正常行为。

非常感谢!

【问题讨论】:

    标签: ruby-on-rails api controller pundit rescue


    【解决方案1】:

    你并不需要rescue_from StandardError,因为这是 Rails 的默认行为。 Rails 有一个名为 PublicExceptions 的中间件,它(大部分)执行您想要的操作,因此您可以让 StandardError 传播。

    它会渲染这个而不是{ error: "Internal Server Error" }

    { 
      status: status, 
      error: Rack::Utils::HTTP_STATUS_CODES.fetch(status, Rack::Utils::HTTP_STATUS_CODES[500]) 
    }
    

    如果出现异常将呈现{ status: 500, error: "Internal Server Error" }。这应该是一个合理的妥协。

    对于开发,您可以考虑调整此中间件。您可以使用config.exceptions_app 进行设置。

    https://guides.rubyonrails.org/configuring.html#rails-general-configuration

    https://api.rubyonrails.org/classes/ActionDispatch/PublicExceptions.html

    https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/public_exceptions.rb#L14

    【讨论】:

    • 非常感谢,伙计!此外,自从我几天前将 RailsConf 2020 演讲标记为观看以来,你的答案就变得不可思议了。
    • 不客气!太棒了,在 Twitter @bruckmayer 上告诉我你的想法!
    【解决方案2】:

    一个简单的快速解决方法是在渲染后使用return。这样下一步就不会运行了。所以在你最后的所有方法中,只需使用return

    例如:

      def user_not_authorized(exception)
        render json: {
          error: "Unauthorized #{exception.policy.class.to_s.underscore.camelize}.#{exception.query}"
       }, status: :unauthorized
    
        return
      end
    

    【讨论】:

    • 我应该在问题中指定,因为这也是我的第一直觉。它不起作用。我认为救援链会干扰正常的render :x and return 行为。
    猜你喜欢
    • 2011-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-10
    • 2015-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多