Grouping Abilities Together

Josh Klina edited this page Aug 16, 2013 · 4 revisions

Let's say we have Authority's default configuration:

config.controller_action_map = {
 :index   => 'read',    # `index` controller action will check `readable_by?`
 :show    => 'read',
 :new     => 'create',  # `new` controller action will check `creatable_by?`
 :create  => 'create',  # ...etc
 :edit    => 'update',
 :update  => 'update',
 :destroy => 'delete'
}
config.abilities =  {
  :create => 'creatable',
  :read   => 'readable',
  :update => 'updatable',
  :delete => 'deletable'
}

We like the granularity of being able to break our CRUD actions down into different abilities, however we would like to have an admin role that can perform all the CRUD functions. We realize that in our views that in order to check if a user has admin permissions we would have to do something like:

- if current_user.can_read?(Article) && current_user.can_create?(Article) && current_us #... etc, etc

And that in our Authorizer classes we would have to check the user's role in each method:

class ArticleAuthorizer < ApplicationAuthorizer
  def self.readable_by?(user)
    user.has_role?(:guest) || user.has_role?(:admin)
  end

  def self.creatable_by?(user)
    user.has_role?(:editor) || user.has_role?(:admin)
  end
  # ... etc, etc
end

It would be a pity if the admin role changed or other new roles can Manage Articles as well as we would have to change every authorizer class method.

To clean things up we can define a new Ability:

config.abilities =  {
  :create => 'creatable',
  :read   => 'readable',
  :update => 'updatable',
  :delete => 'deletable',
  :manage => 'manageable' #new manage ability
}

Add it to our Authorizer:

class ArticleAuthorizer < ApplicationAuthorizer
  def self.readable_by?(user)
    user.has_role?(:guest) || manageable_by?(user)
  end

  def self.creatable_by?(user)
    user.has_role?(:editor) || manageable_by?(user)
  end
  
  # Can now define criteria for managing in one place
  def self.manageable_by?(user)
    user.has_role?(:admin)
  end
end

And clean up our views:

- if current_user.can_manage?(Article)