Search code examples
ruby-on-railspundit

Use pundit to deny users from admin views


I have an admin views where only the administrator is allowed to view. I am using pundit to authorize the application.

How do I deny all users but admin to the admin views without creating policies (and decorate each controller with authorize ) for each admin controllers? If there is a shorter solution.

Thanks


Solution

  • What you're trying to do violates the nature of MVC and is a pretty bad idea.

    While you can authorize in the view:

    # In views
    <% if policy(:dashboard).show? %>
      <%= link_to 'Dashboard', dashboard_path %>
    <% end %>
    

    Thats for authorizing chunks of the view not entire actions.

    The reason for this is that authorization systems like pundit work by raising an exception which is caught in the controller to render the "error" page or redirect. An unauthorised action should also return a different HTTP response code. Doing this when the view has already started to render is to late in the response cycle and would cause a double render error as the server may already have started sending the response.

    Instead you can create a headless policy:

    class AdminPolicy < Struct.new(:user, :admin)
      def admin?
        user.admin?
      end 
    end 
    

    And you can use it like so:

    # app/controllers/concerns/administrated.rb
    module Administrated
      extends ActiveSupport::Concern
    
      included do
        before_action :authorize_admin
      end
    
      def authorize_admin
        authorize(:admin, :admin?)
      end
    end
    
    class ThingsController < ApplicationController
      include Administrated
    end