I'm using Pundit for authorisation, and want to share logic between the policy classes. So far I've been using plain ruby modules and include, but haven't found a good solution for pundit's Scope classes.
For example granting an admin access to records with a particular tag is quite separate from restricting them to only published (not draft or discontinued/deleted) records.
For example
class PagePolicy < ApplicationPolicy
# restrict access to current pages
include PublishedOnlySharedPolicy
# enable section editors to update their tagged content
include TagsAclSharedPolicy
end
module TagsAclSharedPolicy
def update?
admin.in_tag_acl?(record) || super
end
def show?
admin.in_tag_acl?(record) || super
end
def scope
# ... can't do this?
end
end
These modules work fine for the ordinary ACL methods create? update? etc, but scopes are a puzzle since they're class definitions instead of methods.
I'm expecting scope composition to let me take the base class's scope and restrict it by adding where statements as usual, or expand it by using super, pluck, and building a new scope using union.
Is there a clean way to do this without metaprogramming? Or does the library need changing to support dynamic scopes instead of using class definitions?
Why does Pundit use class definitions for scopes anyway?
There's an answer at https://github.com/elabs/pundit/issues/310 if anyone is curious.
Basically add a whitelist ids method to application policy's scope, then override that with normal ruby in each policy's scope class, with any shared scope code going in its own module and being included in the scope.
May be able to metaprogram something even dryer, but that works.