Reputation: 497
I am facing a challenge. A multi level authorization system and a friend told me cancancan could help me out.
I took a read of documentation but couldn't figure it out. So I'll explain here. My goal is to create a sys were:
Also
Now, each user can see only records made by themselves, or from users that are below than, but not above or from other departments.
How should I start with the models and everything?
Upvotes: 1
Views: 243
Reputation: 2498
First of all, you will need to keep track of this tree at database level. In order to do that, you can add a parent_id
reference to the users
table that will reference the user that created that particular user. This column will be empty for those users that were not created by anyone, and would hold the id
of the parent user otherwise. I would highly recommend using a foreign key too, in order to guarantee referential integrity.
Then you will need to define your CanCanCan abilities in a way that this tree structure is traversed properly. You can take as a reference this example derived from the docs:
class Ability
def initialize(user)
can :read, Photo, Book do |resource|
resource.creator.descendant_of? user
end
end
end
I am assuming the User
model has a descendant_of?
method that traverses the tree from the current user towards the root checking whether the given user is a parent of the creator of the resource. A possible implementation could look like this:
# app/models/user.rb
def descendant_of?(target_user)
parent_id == target_user.id || parent&.descendant_of?(target_user)
end
Depending on the characteristics of your users tree, this proposal can quickly become poor in terms of efficiency, as all users from the owner to the root may be loaded from database in order to perform these checks. Here a couple of ideas that could be worth to explore in case you start facing these issues:
parent_ids
column to store the whole list of parent ids. The main drawbacks I see with this proposal is that it adds some overhead if there are changes in the tree, and referential integrity constraints gets lost (AFAIK it is not possible to add a foreign key in this scenario).Upvotes: 1