- Notifications
You must be signed in to change notification settings - Fork0
A better way to do CanCanCan ability classes.
License
mach-kernel/warhol
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
A better way to doCanCanCanAbility classes. Written in pure Ruby withcancancan as its only dependency. Designed to improve code quality in existing projects with CanCan.
CanCan's official documentation says that this is what your ability class should look like:
classAbilityincludeCanCan::Abilitydefinitialize(user)user ||=User.new# guest user (not logged in)ifuser.admin?can:manage,:allelsecan:read,:allendendend
For small applications, this is simple and clear. However, in practice, some of theseAbility classes are 200+ LoC monoliths that encompass the enforcement of many different kinds of permission sets without any clear separation of responsibility. UsingWarhol::Ability allows you to have an individual set of permissions for each role in your domain.
Specify a method on your domain object (for many, anActiveRecord orMongoid model, but any PORO is fine) returning an array of strings, one for each role. Warhol then takes those strings and matches them up to your defined ability classes, applying the access permissions you defined there. Matching is performed on the names of theWarhol::Ability subclass, excluding their namespaces. Here is a database-backed example inspired by the above snippet from CanCan's official docs:
First, some quick configuration. In a Rails project, we suggest this is placed in an initializer:
require'warhol'Warhol::Config.newdo |warhol|# This is the method we invoke belowwarhol.role_accessor=:role_names# Exposes a basic attr_reader. More below.warhol.additional_accessors=['user']end
The domain object can look like this:
classUser <ActiveRecord::Basehas_and_belongs_to_many:rolesdefrole_namesroles.pluck(:name)endend
Some abilities:
classAdministrator <Warhol::Abilitydefine_permissionsdocan:manage,:all# object is always included in scopecan:other_condition,user_id:object.id# user via additional accessorcan:thing_with_condition,user_id:user.idendendclassMember <Warhol::Abilitydefine_permissionsdocan:read,:allendend
Now, we just check the role. People using Rails can just invokecan? from their controller instead of explicitly making a newAbility class:
userputs user.role_names# => ['Member']puts Ability.new(user).can? :manage, @something# => falseThat's it!
To configure Warhol, we create a new singleton configuration class. Every time you invoke::new, the instance is replaced with the one you most recently defined.
Warhol::Config.newdo |warhol|warhol.option=valueend
| Key | Type | Description |
|---|---|---|
| ability_parent | Module | The parent object under which to define theAbility constant. |
| additional_accessors | Array[String] | By default, inside thedefine_permissions block you can access the object you are performing the check on by invokingobject. For the example use case of applying user permissions, passing%w(user) may not be a bad idea. |
| role_accessor (REQUIRED) | Symbol | Accessor used to fetch roles from domain object. |
| role_proc | Proc | If you do not wish to define an accessor, you can pass a block with an arity of 1; the object you are performing the check against will be passed as an argument allowing you to either implement the logic here or delegate it to a service object. |
Some elect to not store role data on user objects, but rather pass users to a service object that provides its authorization level. You can do this with Warhol by providing it with aproc:
Warhol::Config.newdo |warhol|warhol.role_proc=procdo |user|PermissionService.new(user).rolesendend
If for some reason you would like to bindAbility somewhere other thanObject::Ability, you can provide an alternate namespace.
Warhol::Config.newdo |warhol|warhol.ability_parent=Foo::Bar::Bazend
Foo::Bar::Baz::Ability will now be where it is placed.
MIT License
Copyright (c) 2017 David Stancu
Permission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the "Software"), to dealin the Software without restriction, including without limitation the rightsto use, copy, modify, merge, publish, distribute, sublicense, and/or sellcopies of the Software, and to permit persons to whom the Software isfurnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THESOFTWARE.
About
A better way to do CanCanCan ability classes.
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors2
Uh oh!
There was an error while loading.Please reload this page.

