I'm writing API where I need to expose all available permissions with ids and other info to an api user.
I have the following structure
class User < ApplicationRecord
has_many :permissions, dependent: :destroy
end
class Permission < ApplicationRecord
belongs_to :user, dependent: :destroy
end
and I have ability
class Ability
include CanCan::Ability
def initialize(user)
user_permissions(user)
dynamic_permissions(user)
end
def user_permissions(user)
can :manage, :dashboard if user.admin?
end
def dynamic_permissions(user)
user.permissions.each do |permission|
#...
next branch_permissions(permission) if permission.subject_class == 'branch'
end
end
def branch_permissions(permission)
can permission.action.to_sym, Branch, id: permission.allowed_ids
end
and in controller I want to achieve all permissions => can
and cannot
possible for that user. I have checked docs already and found #permissions. But that doesn't work for dynamic permissions that I have for branch
So I expect the following to be done in cancancan way, providing pseudo-code
Ability.new(User.find(params[:id]).dynamic_permissions =>
# {:can=>{:manage=>{"dashboard"=>[]}, :read=>{"Branch"=>['id1', 'id2']}, :index=>{"Branch"=>['id1', 'id2']}, :show=>{"Branch"=>['id1', 'id2']}}, :cannot=>{}}
Current #permissions
cancancan method returns only static permissions that are hardcoded to ability file missing all dynamic evaluation.
{:can=>{:manage=>{"dashboard"=>[]}, :read=>{"Branch"=>[]}, :index=>{"Branch"=>[]}, :show=>{"Branch"=>[]}}, :cannot=>{}}
I know I can modify and write custom method that will fetch all of that, but I'm wondering what is accepted approach achieving this.
ok, it was actually simple. Reading sources helped.
def branch_permissions(permission)
can permission.action.to_sym, Branch, id: permission.allowed_ids
end
this code should be changed to
def branch_permissions(permission)
can permission.action.to_sym, Branch, id: permission.allowed_ids.map(&:to_sym)
end
This method parse_attributes_from_extra_args will treat symbols as attributes for internal state, and then in permissions will show this as I expected. You can serialize those symbols to string then
# Ability.new(User.find(params[:id]).permissions
=> {:can=>{:manage=>{"dashboard"=>[]}, :read=>{"Branch"=>[:id1, :id2]}, :index=>{"Branch"=>['id1', 'id2']}, :show=>{"Branch"=>[:id1', :id2]}}, :cannot=>{}}