cancan/README.rdoc

109 lines
5.4 KiB
Plaintext
Raw Permalink Normal View History

2012-02-15 01:41:18 +00:00
= CanCan {<img src="https://secure.travis-ci.org/ryanb/cancan.png" />}[http://travis-ci.org/ryanb/cancan]
2009-11-17 01:03:54 +00:00
This is the branch for CanCan 2.0 which is in very early development. For a stable release please check out the {master branch}[https://github.com/ryanb/cancan]
Here are some instructions for setting up CanCan 2.0. Try this out and provide feedback in the {issue tracker}[https://github.com/ryanb/cancan/issues].
2009-11-17 05:23:06 +00:00
== Setup
2009-11-17 05:23:06 +00:00
CanCan expects your controllers to have a +current_user+ method. Add some authentication for this (such as Devise[https://github.com/plataformatec/devise], Authlogic[https://github.com/binarylogic/authlogic] or {nifty:authentication}[https://github.com/ryanb/nifty-generators]). See {Changing Defaults}[https://github.com/ryanb/cancan/wiki/Changing-Defaults] to customize this behavior.
To install CanCan, add it to your Gemfile and run the `bundle` command.
gem "cancan", :git => "git://github.com/ryanb/cancan.git", :branch => "2.0"
Next generate an Ability class, this is where your permissions will be defined.
rails g cancan:ability
2009-11-17 05:23:06 +00:00
Add authorization by calling {enable_authorization}[https://github.com/ryanb/cancan/wiki/enable_authorization] in your ApplicationController.
2009-11-17 05:23:06 +00:00
class ApplicationController < ActionController::Base
enable_authorization
end
2009-11-17 05:23:06 +00:00
This will add an authorization check locking down every controller action. If you try visiting a page, a <tt>CanCan::Unauthorized</tt> exception will be raised since you have not granted the user ability to access it.
2010-10-05 23:18:35 +00:00
2011-01-18 19:55:46 +00:00
== Defining Abilities
2011-01-18 19:55:46 +00:00
You grant access to controller actions through the +Ability+ class which was generated above. The +current_user+ is passed in allowing you to define permissions based on user attributes. For example:
2009-11-17 05:23:06 +00:00
if user
can :access, :all
else
can :access, :home
can :create, [:users, :sessions]
end
Here if there is a user he will be able to perform any action on any controller. If someone is not logged in he can only access the home, users, and sessions controllers.
2011-01-18 19:55:46 +00:00
The first argument to +can+ is the action the user can perform. The second argument is the controller name they can perform that action on. You can pass <tt>:access</tt> and <tt>:all</tt> to represent any action and controller respectively.
2011-01-18 19:55:46 +00:00
As shown above, pass an array to either of these will grant permission on each item in the array. It isn't necessary to pass the +new+ action here because CanCan includes some default aliases. See the {Aliases}[https://github.com/ryanb/cancan/wiki/Aliases] page for details.
2009-11-17 05:23:06 +00:00
You can check permissions in any controller or view using the <tt>can?</tt> method.
2009-11-17 05:23:06 +00:00
<% if can? :create, :comments %>
<%= link_to "New Comment", new_comment_path %>
2009-11-17 05:23:06 +00:00
<% end %>
Here the link will only show up the user can create comments.
2009-11-17 05:23:06 +00:00
== Resource Conditions
2009-11-17 05:23:06 +00:00
What if you need to change authorization based on a model's attributes? You can do so by passing a hash of conditions as the last argument to +can+. For example, if you want to only allow one to access projects which he owns you can set the <tt>:user_id</tt>.
can :access, :projects, :user_id => user.id
2009-11-17 05:23:06 +00:00
A block can also be used for complex condition checks just like in CanCan 1, but here it is not necessary.
2010-04-17 18:45:41 +00:00
If you try visiting any of the project pages at this point you will see a <tt>CanCan::InsufficientAuthorizationCheck</tt> exception is raised. This is because the default authorization has no way to check permissions on the <tt>@project</tt> instance. You can check permissions on an object manually using the <tt>authorize!</tt> method.
2011-01-18 19:55:46 +00:00
def edit
@project = Project.find(params[:id])
authorize! :edit, @project
end
2011-01-18 19:55:46 +00:00
However this can get tedious. Instead CanCan provides a +load_and_authorize_resource+ method to load the <tt>@project</tt> instance in every controller action and authorize it.
2009-11-17 05:23:06 +00:00
class ProjectsController < ApplicationController
load_and_authorize_resource
def edit
# @project already loaded here and authorized
2009-11-17 05:23:06 +00:00
end
end
The +index+ (and other collection actions) will load the <tt>@projects</tt> instance which automatically limits the projects the user is allowed to access. This is a scope so you can make further calls to +where+ to limit what is returned from the database.
def index
@projects = @projects.where(:hidden => false)
end
2009-11-17 05:23:06 +00:00
You can check permissions on instances using the <tt>can?</tt> method.
2011-02-22 17:37:53 +00:00
<%= link_to "Edit Project", edit_project_path if can? :update, @project %>
2011-02-22 17:37:53 +00:00
Here it will only show the edit link if the +user_id+ matches.
2011-02-22 17:37:53 +00:00
== Resource Attributes
In CanCan 2.0 it is possible to define permissions on specific resource attributes. For example, if you want to allow a user to only update the name and priority of a project, pass that as the third argument to +can+.
can :update, :projects, [:name, :priority]
If you use this in combination with +load_and_authorize_resource+ it will ensure that only those two attributes exist in <tt>params[:project]</tt> when updating the project. If you do this everywhere it will not be necessary to use +attr_accessible+ in your models.
You can combine this with a hash of conditions. For example, here the user can update all attributes except the price when the product is discontinued.
can :update, :products
cannot :update, :products, :price, :discontinued => true
You can check permissions on specific attributes to determine what to show in the form.
<%= f.text_field :name if can? :update, @project, :name %>
2009-11-17 06:31:27 +00:00