Pundit has a helper method policy_scope
that can be used in controllers and views that basicaly a class finder. It is equivalent to:
@posts = policy_scope(Post)
@posts = PostPolicy::Scope.new(current_user, Post).resolve
Using the helper is a nice approach because you dont have to remember what Scope class you need. This is all fine and well on a world where the app is single teanant or the auth logic to reslove scopes needs no other context but the user and the resource that is being requested.
In our world almost all requests are nested under a company context and require a current user to determine membership role to present certain data.
I just wanted to do something like this:
# list the companies that a user has access to
@communities = policy_scope(Company, current_user).page(params[:page])
class CompanyPolicy < ApplicationPolicy
class Scope < ApplicationPolicy::Scope
def initialize(user,scope, person)
@user = user
@scope = scope
@person = person
@scope = Company.joins(:memberships).uniq.
includes(:links, :logo, :features)
@scope = @scope.where("memberships.user_id" => @person.id)
end
def resolve
if @user.is_a?(SuperUser)
@scope
else
if @person.id == @user.id
@scope
else
raise Pundit::NotAuthorizedError, ApplicationPolicy::DEFAULT_ERROR_MESSAGE
end
end
end
end
end
I made a pull request varvet/pundit#21 to allow policy_scope
to receive parameters. It was a simple addition but it was rejected.
We could continue to mantain a fork of the gem or go with a slightlu more verbose approach:
@communities = policy_scope(PersonCompanies.new(@person).scope).page(params[:page])
class PersonCompanies
def self.policy_class
self
end
def initialize(person)
@person = person
@scope = Company.joins(:memberships).uniq.
includes(:links, :logo, :features)
@scope = @scope.where("memberships.user_id" => person.id)
end
def scope
@scope
end
attr_reader :person, :scope
class Scope < ApplicationPolicy::Scope
def resolve
if @user.is_a?(SuperUser)
@scope
else
if @scope.person.id == @user.id
@scope
else
raise Pundit::NotAuthorizedError, ApplicationPolicy::DEFAULT_ERROR_MESSAGE
end
end
end
end
end
This is not the final iteration of this the wrapper class might be called MembershipScope
and provide different scopes.
What do you think?
Thanks for the hard work and thinking you put into this!
Does passing in an
ActiveRecord::Relation
into thepolicy_scope
help?