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
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.