I’ve been playing about with Devise and CanCan for rails authentication and authorization recently - this great pair of posts from Tony Amoyal have helped a great deal.
I have a User model and a Role model, and wanted to automatically add the :user role to each user whenever roles are assigned. The roles were set in the controller as follows:
1 2 3 4 5 6 | |
… so I wanted to automatically add the :user role when @user.role_ids was set. Initially I tried adding a ‘before_filter’ to the User model:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
Obviously this didn’t work - setting the habtm field in this case happens after the model is saved (as you can see in the 2 lines from the controller above).
Next I tried to over-ride the roles setter in the model :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
The obvious (in hindsight) problem with this is that it is recursive - setting self.role_ids from inside the setter calls itself again, and results in a stack level too deep error. This recursive call can be fixed by changing the line
1
| |
with:
1
| |
or even
1
| |
This fixes the recursion problem, but still doesn’t add the default role properly, due to some complexities with the way habtm is implemented.
After a lot of digging around I came up with a solution that works using alias_method_chain:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
After some testing this seems to do exactly what we need - when @user.role_ids is set, the role_ids_with_add_user_role function is called, and adds the :user role to the list of role ids before saving.