Just ran into an oddity that I didn’t expect (due to a false assumptions) when testing permissions and wanted to send it out to the world.
I have an app with two types of roles; :admin or :user. I am using Rolify in combination with Pundit to perform the role based authorization of REST actions.
I mixin a module containing general purpose authorization classes. I do it this way because permissions schemes tend to change alot and centralization makes it easier to change. You could easily just add these to your pundit policy classes.
def is_admin? user.has_role?(:admin) end def is_user? user.has_role?(:user) end def is_allowed? user.has_role?(:user, record) end
Pretty straight-forward. An administrator has the role of :admin, a user has a role of :user and a :user is only allowed to access records that they are explicitly granted permission on.
My error was the assumption that user.has_role?(:user) would return true if a user had a role of :user explicitly set on any object in the system. In a pundit action it would look something like this.
def index? is_admin? || is_user? end
The problem is that this was returning false unless someone had a :user role set in general, not on a specific instance of a record.
I think code clears this up further, here is the error.
#Assign the user role of :user on a specific object instance User.first.add_role(:user, SomeObject.first) User.first.has_role?(:user) #= false #Assign the user a role of :user User.first.add_role(:user) User.first.has_role?(:user) #= true
So i had to alter this to use see if the User had the role of :user on any object in the system.
#Old definition, broken def is_user? user.has_role?(:user) end #New definition, fixed! def is_user? SomeObject.find_roles(:user, user).any? end
The new is_user? returns true when the user has a role of :user on any SomeObject in the system. Which is exactly what we need.
Lesson learned, I assumed that the method worked a certain way and lost several hours of debugging in my unit tests. I normally will go straight to IRB when i run into anomalies but because i strongly help my assumption I didn’t.