0

I am a little stuck with Pundit: It feels that the solution should be easy - but I am not getting it. Actually I have a bunch of models which are all dependent on one main model. My main model is a script. The script has many roles, many scenes, many costumes, etc. Additionally it has some joined connections like scene.roles. I simply want to authorize the user who created the script to do everything (adding roles, deleting scenes, just everything that is in the scope of her own script) and everybody else to do (and see) nothing. Do I need to create a policy for every model or can I just (re-)use somehow one "script policy"?

How would an authorization look like in a dependent controller (i.e. 'index' in roles or 'new' in scenes)?

The authentication is handled by Device. A user must be logged in to see or do anything. This is my first post on stack overflow, happy to join the community:-)

Alex
  • 1,148
  • 8
  • 30
PixAff
  • 309
  • 4
  • 14
  • Welcome to SO, PixAff! Pundit policies are just POROs, so you can simply create one shared class and just inherit it for every model. In case you you need different permissions on a given model, you can just overwrite the inherited method. – MatFiz Jul 24 '20 at 11:29

2 Answers2

1

Pundit policies are POROs (plain old ruby objects). So you can easily create a policy for the main model:

class ScriptPolicy
  attr_reader :user, :script

  def initialize(user, script)
    @user = user
    @script = script
  end

  def update?
      user.actor?
  end

  def delete?
      user.admin?
  end
end

And then for every model that you have, simply create an empty class definition that inherits from the ScriptPolicy

class ScenePolicy < ScriptPolicy
end

Another approach would be to overwrite the policy name that Pundit is referencing directly in the child model. So assuming that you have a model Scene that shall use the same policy as Script, you can add a method:

class Scene < ActiveRecord::Base
  def self.policy_class
     ScriptPolicy
  end
end

In the latter, you do not need to create empty policy classes for every model, but you trade it for the decreased flexibility in defining specific permissions for models.

MatFiz
  • 973
  • 1
  • 8
  • 25
  • thank you for this (classic) approach! How would (both versions) look like in the controller? Would I `authorize @scene` in the scene controller? And how would I authorize the scene#index method? – PixAff Jul 24 '20 at 16:43
-1

When calling the authorize method in your controller, you can specify the policy class:

authorize @model, policy_class: ScriptPolicy

I find that this solution generates less boilerplate files.

To authorize a scope:

scenes = policy_scope(Scene, policy_scope_class: ScriptPolicy::Scope)

By the way, this is all covered in pundit's README: https://github.com/varvet/pundit

cesartalves
  • 1,507
  • 9
  • 18