Obtaining Pundit Permission to Work with Namespaces in Rails 5

The question is about getting Rails 5 and authorizing Pundit working with namespaces.

With Pundit in the controller I wanted to use policy_scope([:admin, @car]that will use Pundit policy file located at: app/policies/admin/car_policy.rb. I have problems with Pundit working with this namespace - without a namespace, it works fine.

The application is running:

  • Rails 5
  • Configure for authentication
  • Pundit for authorization

My namespace for adminsexample.

The file route.rblooks like this:

# config/routes.rb

devise_for :admins

root: 'cars#index'
resources :cars

namespace :admin do
  root 'cars#index'
  resources :cars
end

Pundit ApplicationPolicy , Pundit authorize: @record = record.is_a?(Array) ? record.last : record

# app/policies/application_policy.rb

class ApplicationPolicy
  attr_reader :user, :record

  def initialize(user, record)
    @user = user
    @record = record.is_a?(Array) ? record.last : record
  end

  def scope
    Pundit.policy_scope!(user, record.class)
  end

  class Scope
    attr_reader :user, :scope

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

    def resolve
      scope
    end
  end
end

Admin::CarsController authorize [:admin, @cars]

class Admin::CarsController < Admin::BaseController
  def index
    @cars = Car.order(created_at: :desc)
    authorize [:admin, @cars]
  end

  def show
    @car = Car.find(params[:id])
    authorize [:admin, @car]
  end
end

Policy Scope

class Admin::CarPolicy < ApplicationPolicy
  class Scope < Scope
    def resolve
      if user?
        scope.all
      else
        scope.where(published: true)
      end
    end
  end

  def update?
    user.admin? or not post.published?
  end
end

Admin::CarsController

class Admin::CarssController < Admin::BaseController
  def index
    # @cars = Car.order(created_at: :desc) without a policy scope
    @cars = policy_scope([:admin, @cars]) # With policy scope / doesn't work because of array.
    authorize [:admin, @cars]
  end

  def show
    # @car = Car.find(params[:id]) without a policy scope
    @car = policy_scope([:admin, @car]) # With policy scope / doesn't work because of array.
    authorize [:admin, @car]
  end
end

, Pundit Admin::CarPolicy. , .

, - policy_scope(Admin::Car), :).

.


Update

Pundit Github: https://github.com/elabs/pundit/pull/391

policy_scope, .

Pudit gem → policy_scope! lib/pundit.rb.

From:

def policy_scope!(user, scope)
  PolicyFinder.new(scope).scope!.new(user, scope).resolve
end

To:

def policy_scope!(user, scope)
  model = scope.is_a?(Array) ? scope.last : scope
  PolicyFinder.new(scope).scope!.new(user, model).resolve
end

: Rails? ?

pundit.rb config/initializer module_eval, , , policy_scope! module Pundit class << self.

, , - , , policy_scope! class << self.

Pundit::module_eval do
  def policy_scope!(user, scope)
    model = scope.is_a?(Array) ? scope.last : scope
    PolicyFinder.new(scope).scope!.new(user, model).resolve
  end
end
+4
1

Medir Pundit Github.

application_policy.rb :

class ApplicationPolicy
  index? show?....

  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      @user = user
      # @scope = scope
      @scope = scope.is_a?(Array) ? scope.last : scope #This fixes the problem
    end

    def resolve
      scope
    end
  end
end

:

policy_scope([:admin, @cars])
+1

Source: https://habr.com/ru/post/1670815/


All Articles