Currently, I'm trying to use policy_scope in index (with pagination) and search controller action, but I've found no way to pass additional arguments to pundit scope. My current workaround is manually creating policy scope and resolve them like this
#user_controllers
@users = UserPolicy::Scope.new(current_admin, User.all(page: params['page'], per_page: params['per_page'], sort_by: params['sort_by'], order: params['order'])).resolve
#user_policy
class Scope < Struct.new(:admin, :scope)
def resolve
if admin.has_permission('index', 'User')
scope
end
end
end
User is not an ActiveRecord class, I'm using Her as the ORM to my REST API.
Is there a better way instead of manually initiate scope like this?
Instead of passing additional arguments to the pundit scope you can chain your query to the scope that's returned (typically an ActiveRecord::Relation). That way, the scope in the UserPolicy is only tasked with determining what users that the current_user is _authorized_ to see.
All your other concerns, like pagination, are then handled in the controller. Please see below for an example.
Users Controller
# users_controller
def index
@users = policy_scope(User).where(archived: false).paginate(@page_options)
end
User Policy
class UserPolicy < ApplicationPolicy
class Scope < Struct.new(:user, :scope)
def resolve
if user.is_admin_user?
scope.all
else
scope.where(account_id: user.account_id)
end
end
end
end
Hope this helps.
Thanks, @johnotander!
Here's a nice way to semantically limit existing scopes.
scope.all.merge(user.companies)
Most helpful comment
Instead of passing additional arguments to the pundit scope you can chain your query to the scope that's returned (typically an
ActiveRecord::Relation). That way, the scope in theUserPolicyis only tasked with determining what users that thecurrent_useris _authorized_ to see.All your other concerns, like pagination, are then handled in the controller. Please see below for an example.
Users Controller
User Policy
Hope this helps.