ruby-on-railsrubyauthorizationpunditruby-3

How to override the pundit authorize method for namespaced policies under ruby 3.x


The pundit documentation suggests that when using namespaced policies for something like Admin views, it can be useful to override the authorize helper in your AdminController to automatically apply the namespacing:

  def authorize(record, query = nil)
    super([:admin, record], query)
  end

This was working fine when my application was running under ruby 2.7, but is failing under ruby 3.x. It does work as expected if I don't supply a value for query, but if I try to specify a policy class in my call to authorize as below, it is ignored.

  @licensee = authorize Licensee.find(params[:id]), policy_class: Admin::LicenseePolicy

For the record the Licensee class uses rails single-table-inheritance (STI), and I am trying to avoid having pundit go looking for non-existent policies for the various subclasses, and just use the "parent" policy class. But in this situation it ignores my policy_class specification and tries/fails to find policies specific to the subclasses.

I figure this relates to ruby 3 changes to hash and keyword argument handling. What is the correct solution to this problem?


Solution

  • The problem can be fixed by explicitly including the policy_class keyword in the authorize method override:

      def authorize(record, query = nil, policy_class: nil)
        super([:admin, record], query, policy_class: policy_class)
      end
    

    or, more generally and probably better, using double-splatted keyword arguments:

      def authorize(record, query = nil, **kwargs)
        super([:admin, record], query, **kwargs)
      end