A new way to cancan
Inspired by one of my student's code, I recently adopted a new way to define authorization with cancan.
Often times, it can be very cumbersome to keep track of all the different resources and roles inside an application. Imagine a hypothetical application that has 3 user roles (admin, employee, and guest). The cancan wiki recommends something like the following:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.role?(:admin)
can :manage, Resource
elsif user.role?(:employee)
can :update, Resource
else
can :read, Resource
end
end
end
This, however, can become quite cumbersome - especially when the roles become very lengthy. You'll be scrolling the whole way down the page, it's easy to accidentally overwrite existing rules, and it just plain sucks. Instead, we can break the roles into their own methods:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
begin
send(user.role)
rescue
Rails.logger.error("Undefined role method for role #{user.role}")
guest
end
end
private
def admin
can :manage, Resource
end
def employee
can :update, Resource
end
def guest
can :read, Resource
end
end
If you have other ways you are using Cancan ability definitions, post a comment!
About Seth
Seth Vargo is a Distinguished Software Engineer at Google. Previously he worked at HashiCorp, Chef Software, CustomInk, and some Pittsburgh-based startups. He is the author of Learning Chef and is passionate about reducing inequality in technology. When he is not writing, working on open source, teaching, or speaking at conferences, Seth advises non-profits.