cancan: Storing in the database vs accessible_by?
We have a UI that lets admins change permissions on our users. So we store these permissions in the database.
Our ability class is:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.role? 开发者_开发知识库:super_admin
can :manage, :all
else
if user.role? :live_trader
can :admin, LiveEvent
end
if user.role? :horse_trader
can :horse_admin, Event
end
if user.role? :channel_admin
can :manage, Channel
end
if user.role? :device_admin
can :manage, Device
end
if user.role? :ost
can :read, Customer.first
end
can do |action, subject_class, subject|
user.roles.find_all_by_action(aliases_for_action(action)).any? do |role|
role.authorizable_type == subject_class.to_s &&
(subject.nil? || role.authorizable_id.nil? || role.authorizable_id == subject.id)
end
end
# can always manage ourselves
can :manage, user
end
end
end
It works fine, except that we can't use accessible_by. We get:
The accessible_by call cannot be used with a block 'can' definition.
I don't see any other way of limiting result sets... Is this a bug or are we doing it wrong?
The error message says it all, really.
There's two ways use cancan using database permissions. One uses the 'can' block, the other uses explicit 'can' permissions. They achieve the same thing.
You can look at https://github.com/ryanb/cancan/wiki/Abilities-in-Database to see the two examples.
I'd say that you'd want to rewrite your 'can' block to:
user.roles.each do |role|
if permission.subject_id.nil?
can permission.action.to_sym, role.authorizable_type.constantize
else
can permission.action.to_sym, role.authorizable_type.constantize, :id => role.authorizable_id
end
end
HTH.
精彩评论