Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/tomasc/mongoid_ability
Custom Ability class that allows CanCanCan authorization library store permissions in MongoDB via the Mongoid gem.
https://github.com/tomasc/mongoid_ability
authorization cancancan mongoid permissions
Last synced: 2 months ago
JSON representation
Custom Ability class that allows CanCanCan authorization library store permissions in MongoDB via the Mongoid gem.
- Host: GitHub
- URL: https://github.com/tomasc/mongoid_ability
- Owner: tomasc
- License: mit
- Created: 2014-12-27T11:50:53.000Z (about 10 years ago)
- Default Branch: master
- Last Pushed: 2024-09-04T07:01:28.000Z (5 months ago)
- Last Synced: 2024-10-31T13:11:43.375Z (3 months ago)
- Topics: authorization, cancancan, mongoid, permissions
- Language: Ruby
- Homepage:
- Size: 223 KB
- Stars: 3
- Watchers: 3
- Forks: 1
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Mongoid Ability
[![Build Status](https://travis-ci.org/tomasc/mongoid_ability.svg)](https://travis-ci.org/tomasc/mongoid_ability) [![Gem Version](https://badge.fury.io/rb/mongoid_ability.svg)](http://badge.fury.io/rb/mongoid_ability) [![Coverage Status](https://img.shields.io/coveralls/tomasc/mongoid_ability.svg)](https://coveralls.io/r/tomasc/mongoid_ability)
Custom `Ability` class that allows [CanCanCan](https://github.com/CanCanCommunity/cancancan) authorization library store permissions in [MongoDB](http://www.mongodb.org) via the [Mongoid](https://github.com/mongoid/mongoid) gem.
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'mongoid_ability'
```And then execute:
```
$ bundle
```Or install it yourself as:
```
$ gem install mongoid_ability
```## Setup
The permissions are defined by a `Lock` that applies to a `Subject` and defines access for its owner – `User` and/or its `Role`.
### Lock
A `Lock` class can be any class that include `MongoidAbility::Lock`. There should be only one such class in an application.
```ruby
class MyLock
include Mongoid::Document
include MongoidAbility::Lockembedded_in :owner, polymorphic: true
end
```This class defines a permission itself using the following fields:
`:subject_type, type: String`
`:subject_id, type: Moped::BSON::ObjectId`
`:action, type: Symbol, default: :read`
`:outcome, type: Boolean, default: false`These fields define what subject (respectively subject type, when referring to a class) the lock applies to, which action it is defined for (for example `:read`), and whether the outcome is positive or negative.
### Subject
All subjects (classes which permissions you want to control) will include the `MongoidAbility::Subject` module.
Each action and its default outcome needs to be defined using the `.default_lock` macro.
```ruby
class MySubject
include Mongoid::Document
include MongoidAbility::Subjectdefault_lock MyLock, :read, true
default_lock MyLock, :update, false
end
```The subject classes can be subclassed. Subclasses inherit the default locks (unless they override them), the resulting outcome being correctly calculated bottom-up the superclass chain.
Additionally the locks can be converted to Mongoid criteria:
```ruby
MySubject.accessible_by(ability, :read)
```### Owner
This `Ability` class supports two levels of inheritance (for example User and its Roles). The locks can be either embedded (via `.embeds_many`) or associated (via `.has_many`). Make sure to include the `as: :owner` option.
```ruby
class MyUser
include Mongoid::Document
include MongoidAbility::Ownerembeds_many :locks, class_name: 'MyLock', as: :owner
has_and_belongs_to_many :roles, class_name: 'MyRole'# override if your relation is named differently
def self.locks_relation_name
:locks
end# override if your relation is named differently
def self.inherit_from_relation_name
:roles
end
end
``````ruby
class MyRole
include Mongoid::Document
include MongoidAbility::Ownerembeds_many :locks, class_name: 'MyLock', as: :owner
has_and_belongs_to_many :users, class_name: 'MyUser'
end
```Both users and roles can be further subclassed.
The owner also gains the `#can?` and `#cannot?` methods, that are delegate to the user's ability. It is then easy to perform permission checks per user:
```ruby
current_user.can?(:read, resource, options)
other_user.can?(:read, ResourceClass, options)
```Ability can be easily obtained as:
```ruby
current_user.ability
```### Caching
The ability object is fully cache-able, which means it is possible to save some precious time on every request (instead of always converting the Lock documents to CanCan rules):
```ruby
class ActionController::Base
def current_ability
@current_ability ||= Rails.cache.fetch([current_user.cache_key, 'ability'].join('/')) do
MongoidAbility::Ability.new(current_user)
end.tap do |ability|
ability.owner ||= current_user
end
end
end
```And on the owner:
```ruby
def ability
@ability ||= Rails.cache.fetch([cache_key, 'ability'].join('/')) do
MongoidAbility::Ability.new(self)
end.tap do |ability|
ability.owner ||= self
end
end
```Of course this assumes the user's `cache_key` updates when any of its locks (or locks stored on its roles) change.
Note the owner has to be assigned after fetching the ability from cache.
### Decoration
To be able to check permissions on decorated objects (for example via the Draper gem) subclass the Ability class as follows:
```ruby
class MyAbility < MongoidAbility::Ability
def can?(action, subject, *extra_args)
while subject.is_a?(Draper::Decorator)
subject = subject.model
endsuper(action, subject, *extra_args)
end
end
```### CanCanCan
The default `:current_ability` defined by [CanCanCan](https://github.com/CanCanCommunity/cancancan) will be automatically overriden by the `Ability` class provided by this gem.
## Usage
1. Setup subject classes and their default locks.
2. Define permissions using lock objects embedded (or associated to) either in user or role.
3. Use standard [CanCanCan](https://github.com/CanCanCommunity/cancancan) helpers (`.authorize!`, `#can?`, `#cannot?`) to authorize the current user.## Contributing
1. Fork it ( https://github.com/tomasc/mongoid_ability/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request