Austin Story

Ruby, Rails and Javascript Blog

Powered by Genesis

Pundit and Rolify Testing with Rails

September 21, 2014 By Austin Story Leave a Comment

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.

[ruby]
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
[/ruby]

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.

[ruby]
def index?
is_admin? || is_user?
end
[/ruby]

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.

[ruby]
#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
[/ruby]

So i had to alter this to use see if the User had the role of :user on any object in the system.

[ruby]
#Old definition, broken
def is_user?
user.has_role?(:user)
end

#New definition, fixed!
def is_user?
SomeObject.find_roles(:user, user).any?
end
[/ruby]

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.

Filed Under: Integrations, Minitest, Ruby, Ruby on Rails Tagged With: Pundit, Rails, Rolify, ruby on Rails

Categories

  • AngularJS
  • Books
  • Devise
  • Elasticsearch
  • ES6
  • Information Security
  • Integrations
  • Javascript
  • Linux
  • Minitest
  • PhoneGap
  • Programming
  • React
  • Redux
  • Ruby
  • Ruby on Rails
  • Stripe
  • Testing
  • Theory
  • TypeScript
  • Uncategorized
  • Vue
  • Webpack