代码之家  ›  专栏  ›  技术社区  ›  OKMantis

简单控制器的双重渲染错误

  •  1
  • OKMantis  · 技术社区  · 5 年前

    我的api rails应用程序中出现了一个奇怪的错误:

    AbstractController::DoubleRenderError in Api::V1::AdsController#restaurant
    Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".
    

    我找到了这一页 https://api.rubyonrails.org/classes/ActionController/Base.html 关于双重渲染,但我并没有真正理解它们的含义以及它如何应用到我的情况。

    我的控制器里有这个:

    class Api::V1::AdsController < Api::V1::BaseController
      before_action :set_ad, only: [ :show ]
    
      def index
        @ads = policy_scope(Subcategory.find_by(nombre: "Restaurantes").ads)
      end
    
      def restaurant
        @restaurants = policy_scope(Subcategory.find_by(nombre: "Restaurantes").ads)
      end
    
      def show
      end
    
      private
    
      def set_ad
        @ad = Ad.find(params[:id])
        authorize @ad
      end
    end
    

    在我看来:

    Rails.application.routes.draw do
      devise_for :users
      namespace :api, defaults: { format: :json } do
        namespace :v1 do
          resources :ads, only: [ :index, :show ] do
            collection do
              get 'restaurant', to: 'ads#restaurant'
            end
          end
        end
      end
      root to: 'pages#home'
      # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
    end
    

    我有三种观点: 索引.json.jbuilder:

    json.array! @ads do |ad|
      json.extract! ad,
      :id,
      :empresa,
      :direccion_principal,
      :tel,
      :email_principal,
      :web,
      :facebook,
      :instagram,
      :twitter,
      :isla
    end
    

    restaurant.json.jbuilder=与index相同

    显示.json.jbuilder:

    json.extract! @ad, :id, :empresa, :direccion_principal
    

    有人能看到这里的问题吗?

    编辑:

    AdPolicy:

    class AdPolicy < ApplicationPolicy
      class Scope < Scope
        def resolve
          scope.all
        end
      end
    
      def show?
        true
      end
    end
    

    基本控制器:

    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
    
    1 回复  |  直到 5 年前
        1
  •  0
  •   OKMantis    5 年前

    我找到了自己问题的答案。这和BaseController有关。我忘了加上:餐厅到后措施:验证已授权和验证策略范围。下面的BaseController现在可以工作了。

    class Api::V1::BaseController < ActionController::API
      include Pundit
    
      after_action :verify_authorized, except: [:index, :restaurant]
      after_action :verify_policy_scoped, only: [:index, :restaurant, :beach_restaurant, :cafe]
    
      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