Reputation: 3550
I have a Rails 3 app, where i use CanCan for authorization, but i am looking for something that suits my needs better. My authorizations is not very role based, but really more situational.
The application is for managing daily dinner clubs at a college/dorm, where the people takes turn making dinner for the rest. A chef have therefore more permissions for the dinner club he is responsible for (like changing the menu), and a participant have more permissions (like adding guests) then one who is not participating in that single dinner club.
What i need is therefore some authorization system that depends on the relationship between the user and the dinner club or kitchen (a kitchen have many dinner clubs), not the users role.
If it helps, are my current cancan abilities here (as you see they are pretty complex)
# In ability.rb
def initialize(user)
# edit (like changing time or menu) for a dinner club
can :edit, DinnerClub do |dinner_club|
dinner_club.is_chef?(user) &&
!dinner_club.canceled?
end
# open or close a dinner club
can [:open, :close], DinnerClub do |dinner_club|
!dinner_club.passed? &&
dinner_club.is_chef?(user)
end
# cancel or resume a dinner club
can [:cancel, :resume], DinnerClub do |dinner_club|
!dinner_club.passed? &&
dinner_club.is_chef?(user)
end
# register or unregister for at specific dinner club
can [:register, :unregister], DinnerClub do |dinner_club|
dinner_club.open? &&
(dinner_club.kitchen_id == user.kitchen_id || dinner_club.kitchen.open_registrations?) &&
!dinner_club.is_chef?(user)
end
# add guests to a dinner club
can [:add_guests], DinnerClub do |dinner_club|
dinner_club.open? &&
(dinner_club.kitchen_id == user.kitchen_id || dinner_club.kitchen.open_registrations?) &&
dinner_club.registered?(user)
end
# take the dinner club from another use if the dinner club is canceled
can [:take], DinnerClub do |dinner_club|
dinner_club.canceled? &&
(dinner_club.kitchen_id == user.kitchen_id || dinner_club.kitchen.open_registrations?) &&
!dinner_club.passed? &&
!dinner_club.is_chef?(user)
end
# create a new dinner club
can [:create], DinnerClub do |dinner_club|
(dinner_club.kitchen_id == user.kitchen_id || dinner_club.kitchen.open_registrations?)
end
# comment on existing dinner clubs
can [:comment], DinnerClub do |dinner_club|
dinner_club.registered?(user)
end
# can see dinner clubs for this kitchen
can :read, Kitchen do |kitchen|
(kitchen.id == user.kitchen_id || kitchen.open_registrations?)
end
# can manage the kitchen, like changing name and configuration options
can :manage, Kitchen, admin_id: user.id
end
Upvotes: 0
Views: 113
Reputation: 6274
You can rewrite most of these blocks in CanCan to make them a lot less complex.
can :edit, DinnerClub, cancelled: false, chef_id: user.id
# open or close a dinner club
can [:open, :close], DinnerClub, passed: false, chef_id: user.id
# take the dinner club from another use if the dinner club is canceled
can [:take], DinnerClub, cancelled: true, kitchen_id: user.kitched_id, passed: false
can [:take], DinnerClub, cancelled: true, kitchen: { open_registrations: true }, passed: false
cannnot [:take], DinnerClub, chef_id: user.id
This is assuming the cancelled?
and passed?
methods are derived from boolean attributes on the DinnerClub model and that the is_chef?
method checks a chef_id. But it illustrates the idea.
CanCan is mostly used to define abilities based on resources, so I would go with that.
Upvotes: 1