Pundit authorization in index
Asked Answered
B

2

11

I have been recently reading through the pundit gem's README and noticed that they never authorize the index view within a controller. (Instead they use scope).

They give good reasoning for this, as an index page generally contains a list of elements, by controlling the list that is generated you effectively control the data on the page. However, occasionally it may be desired to block access to even the index page itself. (Rather than allowing access to a blank index page.) My question is what would be the proper way to perform this?

I have so far come up with several possibilities, and have the following classes:

  • A model MyModel
  • A controller MyModelsController
  • A policy MyModelPolicy

In my index method of my controller, the recommended method to solve this would be as follows:

def index
  @my_models = policy_Scope(MyModel)
end

This will then allow access to the index page, but will filter the results to only what that use can see. (E.G. no results for no access.)

However to block access to the index page itself I have arrived at two different possibilities:

def index
  @my_models = policy_Scope(MyModel)
  authorize @my_models
end

or

def index
  @my_models = policy_Scope(MyModel)
  authorize MyModel
end

Which of these would be the correct path, or is there a different alternative that would be preferred?

Bonefish answered 25/8, 2016 at 14:34 Comment(2)
What's the criteria for authoring or not? Whether the scope is empty or not?Capillarity
I've come across the same problem. I might be wrong but I think that the point is that it's not Pundit's job to block access to the index page. From an authorization point of view, having an empty index page is the same as having no index: the user is not authorized to see any record. Sometimes, as in your case, the user should not even see a link to the index page, but then that's a usability concern, not an authorization concern, therefore it's not Pundit's business.Marble
H
11
class MyModelPolicy < ApplicationPolicy
  class Scope < Scope
    def resolve
      if user.admin?
        scope.all
      else
        raise Pundit::NotAuthorizedError, 'not allowed to view this action'
      end
    end
  end
end
Homogeneity answered 21/6, 2018 at 10:45 Comment(1)
I like it, never thought about doing it that way.Bonefish
D
8

Policy,

class MyModelPolicy < ApplicationPolicy
  class Scope < Scope
    def resolve
      if user.admin?
        scope.all
      else
        scope.where(user: user)
      end
    end
  end

  def index?
    user.admin?
  end
end

Controller,

def index
  @my_models = policy_scope(MyModel)
  authorize MyModel
end
Dunite answered 2/12, 2016 at 13:56 Comment(1)
I hoped Pundit had a cleaner solution, althrough it worksHarlin

© 2022 - 2024 — McMap. All rights reserved.