0

I am referring to my own question Rails Nested Resources with Pundit Allowing Index and finally came up with a working solution but is there not any much better solution defining scope.where(?) or scope.select(?) in the property_policy? How to get all the properties that only belongs to one specific deal using the pundit resolve method?

What I finally did :

properties_controller.rb

class PropertiesController < ApplicationController
before_action :set_deal, except: [:index, :all]
before_action :set_property, only: [:show, :edit, :update, :destroy]

def all
  @properties = Property.all
  authorize @properties
end

def index
  @deal = Deal.find(params[:deal_id])
  @properties = policy_scope(Deal)
end

def set_deal
  @deal = Deal.find(params[:deal_id])
  # pundit ######
  authorize @deal
  ###############
end
(...)
end

property_policy.rb

class PropertyPolicy < ApplicationPolicy
class Scope < Scope
def resolve
  scope.all if user.admin?
end
def all?
  user_is_admin?
end
def user_is_admin?
  user.try(:admin?)
end 
(...)
end

What I'd like better:

properties_controller.rb

def index
  @deal = Deal.find(params[:deal_id])
  @properties = policy_scope(Property) # => for # @properties = @deal.properties
  authorize @deal
end

and in the property_policy.rb something like

def resolve
  # scope.where(???) if user.admin? # only an admin user can see the @deal.properties
  # or any other solution using scope
 end

As a reminder 1 deal has many properties and 1 property belongs to one specific deal. My routes are nested deals/id/properties except for the full list of properties I have simple "/properties". Thanks a lot for helping.

** UPDATE **

I finally went for

properties_controller.rb

def index
  @deal = Deal.find(params[:deal_id])
  @properties = policy_scope(@deal.properties)
  authorize @properties, :index?
end

and in property_policy.rb

class PropertyPolicy < ApplicationPolicy
  class Scope < Scope
    def resolve
      user.admin? ? scope.all : scope.none
    end
  end
  def index?
    user_is_admin?
  end
  def user_is_admin?
    user.try(:admin?)
  end
end

Not sure if it is the proper way

Community
  • 1
  • 1
nicodo
  • 47
  • 7

1 Answers1

0

What you want to do is pass a scope to the policy - not just a class.

@properties = policy_scope(@deal.policies)

class PropertiesPolicy
  class Scope < Scope
    def resolve
      user.admin? ? scope.all : scope.none
    end
  end
end

Another problem with your controller is that authorize @deal will call DealsPolicy#index? which is not what you want.

To authorize an index action you want to call authorize with the model class (and not an instance):

def index
  authorize Property # calls PropertiesPolicy#index?
  @deal = Deal.find(params[:deal_id])
  @properties = policy_scope(@deal.properties)
end

In that case you don't have to do anything special in your Scope#resolve method really. Just return scope since you can assume at that point that the user is an admin.

Steve Folly
  • 8,327
  • 9
  • 52
  • 63
max
  • 96,212
  • 14
  • 104
  • 165
  • Thanks a lot Max but it does not work using authorize :index I get the error `unable to find policy "IndexPolicy" for ":index"` If I don't authorize anything in the index method any user can see the properties which is not what I want either. Also `user.admin? ? scope.all : scope.none` is not really what I want it's more like either all or don't give access to the page at all. – nicodo Feb 09 '17 at 14:29
  • Max I think I understand what you mean now. Please see my update. I have defined both a scope and an index? method in the property_policy and changed `authorize @properties, :index?` in the controller. Is that what you meant? I would be grateful if you can confirm that I understand correctly that you need to define both a scope and an index? method to restrict the visibility of the page. Thanks – nicodo Feb 09 '17 at 16:36
  • Ah, sorry I missread the docs - if you don't have an instance you want to call authorize with the class `authorize Property` you should call this right at the top of the method to throw authenticated users out. See my edit – max Feb 10 '17 at 01:15
  • If you call it with a symbol it should be `authorize :properties, :index?`which is how you deal with headless controllers. – max Feb 10 '17 at 01:28
  • Thanks Max for your explanation – nicodo Feb 13 '17 at 06:44