109 lines
5.4 KiB
Plaintext
109 lines
5.4 KiB
Plaintext
= CanCan {<img src="https://secure.travis-ci.org/ryanb/cancan.png" />}[http://travis-ci.org/ryanb/cancan]
|
|
|
|
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].
|
|
|
|
|
|
== Setup
|
|
|
|
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
|
|
|
|
Add authorization by calling {enable_authorization}[https://github.com/ryanb/cancan/wiki/enable_authorization] in your ApplicationController.
|
|
|
|
class ApplicationController < ActionController::Base
|
|
enable_authorization
|
|
end
|
|
|
|
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.
|
|
|
|
|
|
== Defining Abilities
|
|
|
|
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:
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
You can check permissions in any controller or view using the <tt>can?</tt> method.
|
|
|
|
<% if can? :create, :comments %>
|
|
<%= link_to "New Comment", new_comment_path %>
|
|
<% end %>
|
|
|
|
Here the link will only show up the user can create comments.
|
|
|
|
|
|
== Resource Conditions
|
|
|
|
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
|
|
|
|
A block can also be used for complex condition checks just like in CanCan 1, but here it is not necessary.
|
|
|
|
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.
|
|
|
|
def edit
|
|
@project = Project.find(params[:id])
|
|
authorize! :edit, @project
|
|
end
|
|
|
|
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.
|
|
|
|
class ProjectsController < ApplicationController
|
|
load_and_authorize_resource
|
|
def edit
|
|
# @project already loaded here and authorized
|
|
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
|
|
|
|
You can check permissions on instances using the <tt>can?</tt> method.
|
|
|
|
<%= link_to "Edit Project", edit_project_path if can? :update, @project %>
|
|
|
|
Here it will only show the edit link if the +user_id+ matches.
|
|
|
|
|
|
== 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 %>
|
|
|