Last active
June 7, 2022 20:04
-
-
Save JoshCheek/62484a409b078f9ce89931fc7a610002 to your computer and use it in GitHub Desktop.
Extending CanCanCan, abilities
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'cancan' | |
# Some models | |
Post = Struct.new(:author, :published, :body) { alias published? published } | |
User = Struct.new(:name, :admin) { alias admin? admin } | |
# Abilities | |
class CommonAbility | |
include CanCan::Ability | |
def initialize(user) | |
can(:read, Post) { |post| post.published? || post.author == user } | |
can(:edit, Post) { |post| post.author == user } | |
can :favourite, Post | |
end | |
end | |
class AdminAbility | |
include CanCan::Ability | |
def initialize(admin) | |
can :edit, Post | |
cannot :favourite, Post | |
end | |
end | |
# Test data | |
reader = User.new 'reader', false | |
author = User.new 'author', false | |
admin = User.new 'admin', true | |
published_post = Post.new author, true, 'My finished thoughts' | |
private_post = Post.new author, false, 'My unfinished thoughts' | |
reader_ability = CommonAbility.new(reader) | |
author_ability = CommonAbility.new(author) | |
admin_ability = CommonAbility.new(admin).merge(AdminAbility.new(admin)) # <-- must be instantiated like this (must merge admin into common, and common must be a new instance b/c `merge` mutates it) | |
# Test falling back to common enabled static ability: reading a published post (everyone can, via common ability) | |
reader_ability.can? :read, published_post # => true | |
author_ability.can? :read, published_post # => true | |
admin_ability.can? :read, published_post # => true | |
# Test falling back to common enabled dynamic ability: reading a private post (author can via common ability) | |
reader_ability.can? :read, private_post # => false | |
author_ability.can? :read, private_post # => true | |
admin_ability.can? :read, private_post # => false | |
# Test overriding to grant an ability: editing post (author can via common ability, admin can via admin ability) | |
reader_ability.can? :edit, published_post # => false | |
author_ability.can? :edit, published_post # => true | |
admin_ability.can? :edit, published_post # => true | |
# Test overriding to remove an ability: favouriting a post (admin cannot, b/c via admin ability) | |
reader_ability.can? :favourite, published_post # => true | |
author_ability.can? :favourite, published_post # => true | |
admin_ability.can? :favourite, published_post # => false | |
# Test abilities that were never defined: deleting a post (no one can) | |
reader_ability.can? :delete, published_post # => false | |
author_ability.can? :delete, published_post # => false | |
admin_ability.can? :delete, published_post # => false |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment