Moulin Rouge offers a custom and easy DSL to manage your authorizations and groups of access with CanCan. The main feature is the ability to split your authorizations in many ruby files, that are automatically pushed to CanCan authorization system. It is also decoupled from any role system giving you flexibility.
There are a bunch of examples bellow to show you how to get started and explaining all features.
Add the gem to your Gemfile:
And install it
Run the generator to install the roles and permissions structure:
rails g moulin_rouge:install
Generate a permission file:
rails g moulin_rouge:auth <name>
Add your permissions to newly created file:
class UserAuthorization < :: role :name do can :read, :something end end
By default your
current_user method should respond to
is?, but you can change this method to match your role system at the configuration.
First of all, you have to accept that the role registering belongs to the ruby code. Organizing this ruby files it's a really important issue to any large application.
When you run:
bundle g moulin_rouge:install
This will create the following folder structure:
root | app/ | | authorizations/ | config/ | | initalizers | | | moulin_rouge.rb
All your authorization files will be stored inside the
app/authorizations folder. Just create a ruby file inside and the definitions will be automatically defined.
class UserAuthorization < :: role :superuser do can :manage, :all end role :editors do can :manage, Articles end role :authors do can :manage, Article do |article| article.user_id == current_user.id end end end
Note that the
can method is the same for defining abilities in CanCan, and will be passed as they are on the Ability class. See Defining Abilities for more information on what you
Also, the others CanCan methods are avaliable (
cannot?) and will act like expected.
A group is an easy way to organize your authorization. All groups with the same name, will have their abilities and authorizations nested together.
The group will delegate all abilities defined inside of it, to their childrens, so any role or group will have the same abilities defined in the parent. Also the group is not an avaliable role, they only serve has namespaces.
class UserAuthorization < :: group :marketing do can :read, Dashboard role :manager do can :manage, Proposal end role :salesman do can :manage, Proposal, :user_id => current_user.id end end end
To avoid name conflicts, whenever you have a nested roles or groups, their name will be prefixed with the parent name separeted by a
_ underscore just like they were namespaced.
Following the example above, will generate two roles:
::. # => [:marketing_manager, :marketing_salesman] # => :marketing_manager => can :read, Dashboard, can :manage, Proposal # => :marketing_salesman => can :read, Dashboard, can :manage, Proposal, :user_id => current_user.id
When you have nested rules, they will act has namespaces, no ability will be shared unless is explicited with the
class UserAuthorization < :: role :marketing do can :manage, Proposal role :salesman do can :read, Proposal end end end
Following the example above, this will generate two roles with the abilities:
::. # => [:marketing, :marketing_salesman] # => :marketing => can :manage, Proposal # => :marketing_salesman => can :read, Proposal
If you want extend the abilities from a role to another, MoulinRouge let you
include them automatically. All the abilities from the target will be appended to the caller.
Only roles can be included, and if you provide a name that is not defined, a
RoleNotFound will be raised. Notice by the example bellow, that you should provide the full name of the role in order to find them.
class UserAuthorization < :: group :marketing do role :admin do can :do, :something end end role :super do include :marketing_admin end end
. do |config| # Cache authorizations config.cache = Rails.env.production? # Path for search the authorizations files config.path = 'app/authorizations/**/*.rb' # Method name that will send to the user to test if the role is assigned to him config.test_method = :is? # Your user model config.model = User # The method name that will access the current user information config.model_instance = :current_user end
This session is in experimental development and will be part of the next release!
For those who does not like the
load_and_authorize_resource method from CanCan, here is provided a cleaner and more flexible solution through
MoulinRouge::CanCan::Responder bellow there are instruction to activate them.
Create the file
lib/application_responder.rb with the following:
require 'moulin_rouge/cancan/responder' class ApplicationResponder < ActionController::Responder include :::: end
And on your
application_controller.rb just add the responder:
require 'application_responder' class ApplicationController < ActionController::Base protect_from_forgery self.responder = ApplicationResponder ... end
More about the
bundle exec guard
And it will perform all tests, and reload every time you implement something new. Also you can follow the test coverage by simplecov.
A little of history
Copyrights 2012 Edson Hilios edson (at) hilios (dot) com (dot) br
This software is licensed under MIT-LICENSE