3

I'm getting the following error when a user isn't allowed to see a page with authorization rules by pundit:

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".

This is the application_controller.rb:

class ApplicationController < ActionController::Base    
  # Includes Authorization mechanism
    include Pundit

  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  # Globally rescue Authorization Errors in controller.
  # Returning 403 Forbidden if permission is denied
  rescue_from Pundit::NotAuthorizedError, with: :permission_denied

  # Enforces access right checks for individuals resources
  # after_filter :verify_authorized, :except => :index

  # Enforces access right checks for collections
  # after_filter :verify_policy_scoped, :only => :index

  private

  def permission_denied
    flash[:error] = "You don't have the proper permissions to view this page. If you think you are supposed to then please contact us at permissions@inrtracker.com"
    # this is giving a redirect loop error
    redirect_to(request.referrer || root_path)
  end
end

stat_policy.rb:

class StatPolicy
  attr_reader :current_user, :model

  def initialize(current_user, model)
    @current_user = current_user
    @stat = model
  end

  def index?
    @current_user.admin?
  end
end

stats_controller.rb:

class StatsController < ApplicationController
  after_action :authorize_stat

  def index
    @stats = Stat.all
    @stat = Stat.new
    render layout: "stat_layout"
  end

  private
    def authorize_stat
      authorize @stat
    end

    # Use callbacks to share common setup or constraints between actions.
    def set_stat
      @stat = Stat.find(params[:id])
    end

end
Pavan Katepalli
  • 2,372
  • 4
  • 29
  • 52

3 Answers3

7

There's a strange order of operations that occurs with the after_action. If you set the response_body to nil, it should fix your problem.

  def permission_denied
    flash[:error] = "You don't have the proper permissions to view this page. If you think you are supposed to then please contact us at permissions@inrtracker.com"
    self.response_body = nil # This should resolve the redirect root.
    redirect_to(request.referrer || root_path)
  end
John Otander
  • 138
  • 1
  • 1
  • 5
  • could you please explain why setting up 'response_body' to nil it is solving the issue? please. – nisevi Jun 10 '16 at 17:18
2

The accepted answer did not work for me. My problem ended up being that Turbolinks was causing all links to be double submitted. I do not know the original cause of my Turbolinks issue, but I disabled Turbolinks and everything now works fine.

Garrett Berneche
  • 1,049
  • 1
  • 9
  • 13
0

According to Garrett's solution, the issue is caused by Turbolinks in combination with the Rails rendering flow. Instead of removing Turbolinks, which is extremely useful, I suggest to place a:

data-turbolinks="false"

On the links pointing to the pages causing the issue. In my case, it was just happening on pages with forms, like "new" actions.

Rubén_ic
  • 137
  • 2
  • 10