= Canard == Overview Canard brings CanCan and RoleModel together to make role based authorization in Rails easy. Your ability definitions gain their own folder and a little structure. The easiest way to get started is with the Canard generator. Canard progressively enhances the abilities of the model by applying role abilities on top of the models base abilities. A User model with :admin and :manager roles would be defined: class User < ActiveRecord::Base acts_as_user :roles => :manager, :admin end If a User has both the :manager and :admin roles Canard will apply the abilities in the following order. First it will look for a users abilities, then it will look for the roles in the order they are defined e.g. app/abilities/users.rb app/abilities/manager.rb app/abilities/admin.rb Therefore each the later abilities only need to build on their predecessors. == Usage To generate some abilities for the User. $ rails g canard:ability user can:[read,create]:[account,statement] cannot:destroy:account create app/abilities/users.rb invoke rspec create spec/abilities/user_spec.rb Generates an ability folder in Rails root and an associated spec; app.abilities/ users.rb spec/abilities/ users_spec.rb The resulting app/abilities/users.rb will look something like this; Canard::Abilities.for(:user) do can [:read, :create], Account cannot [:destroy], Account can [:read, :create], Statement end And it's associated test spec/abilities/users_spec.rb; require_relative '../spec_helper' require "cancan/matchers" describe Ability, "for :user" do before do @user = Factory.create(:user_user) end subject { Ability.new(@user) } describe 'on Account' do before do @account = Factory.create(:account) end it { should be_able_to( :read, @account ) } it { should be_able_to( :create, @account ) } it { should_not be_able_to( :destroy, @account ) } end # on Account describe 'on Statement' do before do @statement = Factory.create(:statement) end it { should be_able_to( :read, @statement ) } it { should be_able_to( :create, @statement ) } end # on Statement end Now lets generate some abilities for the manager and admin. $ rails g canard:ability admin can:manage:[account,statement] $ rails g canard:ability manager can:edit:statement Gives us two new sets of abilities in the abilities folder. Canard will apply these abilities by first loading the ability for the User model and then apply the abilities for each role the current user has. If there is no user (i.e. logged out) Canard creates a guest and looks for a guest ability to apply so: $ rails g canard:ability guest can:create:user Would generate an ability for a not logged in user to signup. Obviously the generators are just a starting point and should be used only to get you going. I strongly suggest that every new model you create you add to the abilities as the specs are easy to write and CanCan definitions are very clear and simple. == Scopes The :acts_as_user method with automatically define some named scopes for each role. For the example User model above it will define the following scopes; User.admins:: return all the users with the admin role User.non_admins:: return all the users without the admin role User.managers:: return all the users with the manager role User.non_managers:: return all the users without the manager role In addition to the role specific scopes it also adds some general scopes; User.with_any_role(roles):: return all the users with any of the specified roles User.with_all_roles(roles):: return only the users with all the specified roles == Installation === Rails 3.x Add the canard gem to your Gemfile. In Gemfile: gem "canard" Add the `roles_mask` field to your user table: rails g migration add_roles_mask_to_users roles_mask:integer rake db:migrate That's it! === Rails 2.x Sorry you are out of luck with Rails 2.x Canard has only been written and tested with Rails 3.x. I'll be happy to accept pull requests for tested Rails 2.x updates if anybody is game. == Supported ORM's Canard is ORM agnostic. ActiveRecord and Mongoid (thanks David Butler) adapters are currently implemented. New adapters can easily be added, but you'd need to check CanCan can also support your adapter. == Further reading Canard stands on the sholders of Ryan Bates' CanCan and Martin Rehfeld's RoleModel. You can read more about defining abilities on the CanCan wiki (https://github.com/ryanb/cancan/wiki). Canard implements the Ability class for you so you don't need the boilerplate code from Ryan's example; class Ability include CanCan::Ability def initialize(user) user ||= User.new # guest user (not logged in) if user.admin? can :manage, :all else can :read, :all end end end The Canard equivalent for non admins would be; Canard::Abilities.for(:user) do can :read, :all end And for Admins; Canard::Abilities.for(:admin) do can :manage, :all end Under the covers Canard uses RoleModel (https://github.com/martinrehfeld/role_model) to define roles. RoleModel is based on Ryan Bates' suggested approach to role based authorization which is documented in the CanCan wiki (https://github.com/ryanb/cancan/wiki/role-based-authorization). == Note on Patches/Pull Request * Fork the project. * Make your feature addition or bug fix. * Add tests for it (when I have some). This is important so I don't break it in a future version unintentionally. * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore it when I pull) * Send me a pull request. Bonus points for topic branches. == Contributors git log | grep Author | sort | uniq * James McCarthy * Joey Geiger * Morton Jonuschat * David Butler If you feel like contributing there is a TODO list in the root with a few ideas and opportunities! == Credits Thanks to Ryan Bates for creating the awesome CanCan (http://wiki.github.com/ryanb/cancan) and Martin Rehfeld for implementing Role Based Authorization in the form of RoleModel (http://github.com/martinrehfeld/role_model). == Copyright Copyright (c) 2011 James McCarthy, released under the MIT license