diff --git a/README.rdoc b/README.rdoc
index e87c71f..e72fb29 100644
--- a/README.rdoc
+++ b/README.rdoc
@@ -1,111 +1,108 @@
= CanCan
-Wiki[https://github.com/ryanb/cancan/wiki] | RDocs[http://rdoc.info/projects/ryanb/cancan] | Screencast[http://railscasts.com/episodes/192-authorization-with-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]
-CanCan is an authorization library for Ruby on Rails which restricts what resources a given user is allowed to access. All permissions are defined in a single location (the +Ability+ class) and not duplicated across controllers, views, and database queries.
+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].
-== Installation
+== Setup
-In Rails 3, add this to your Gemfile and run the +bundle+ command.
+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.
- gem "cancan"
+To install CanCan, add it to your Gemfile and run the `bundle` command.
-In Rails 2, add this to your environment.rb file.
+ gem "cancan", :git => "git://github.com/ryanb/cancan.git", :branch => "2.0"
- config.gem "cancan"
-
-Alternatively, you can install it as a plugin.
-
- rails plugin install git://github.com/ryanb/cancan.git
-
-
-== Getting Started
-
-CanCan expects a +current_user+ method to exist in the controller. First, set up some authentication (such as Authlogic[https://github.com/binarylogic/authlogic] or Devise[https://github.com/plataformatec/devise]). See {Changing Defaults}[https://github.com/ryanb/cancan/wiki/changing-defaults] if you need different behavior.
-
-
-=== 1. Define Abilities
-
-User permissions are defined in an +Ability+ class. CanCan 1.5 includes a Rails 3 generator for creating this class.
+Next generate an Ability class, this is where your permissions will be defined.
rails g cancan:ability
-See {Defining Abilities}[https://github.com/ryanb/cancan/wiki/defining-abilities] for details.
+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 CanCan::Unauthorized exception will be raised since you have not granted the user ability to access it.
-=== 2. Check Abilities & Authorization
+== Defining Abilities
-The current user's permissions can then be checked using the can? and cannot? methods in the view and controller.
+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 can? :update, @article %>
- <%= link_to "Edit", edit_article_path(@article) %>
+ 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 :access and :all 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 can? method.
+
+ <% if can? :create, :comments %>
+ <%= link_to "New Comment", new_comment_path %>
<% end %>
-See {Checking Abilities}[https://github.com/ryanb/cancan/wiki/checking-abilities] for more information
+Here the link will only show up the user can create comments.
-The authorize! method in the controller will raise an exception if the user is not able to perform the given action.
- def show
- @article = Article.find(params[:id])
- authorize! :read, @article
+== 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 :user_id.
+
+ 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 CanCan::InsufficientAuthorizationCheck exception is raised. This is because the default authorization has no way to check permissions on the @project instance. You can check permissions on an object manually using the authorize! method.
+
+ def edit
+ @project = Project.find(params[:id])
+ authorize! :edit, @project
end
-Setting this for every action can be tedious, therefore the +load_and_authorize_resource+ method is provided to automatically authorize all actions in a RESTful style resource controller. It will use a before filter to load the resource into an instance variable and authorize it for every action.
+However this can get tedious. Instead CanCan provides a +load_and_authorize_resource+ method to load the @project instance in every controller action and authorize it.
- class ArticlesController < ApplicationController
+ class ProjectsController < ApplicationController
load_and_authorize_resource
-
- def show
- # @article is already loaded and authorized
+ def edit
+ # @project already loaded here and authorized
end
end
-See {Authorizing Controller Actions}[https://github.com/ryanb/cancan/wiki/authorizing-controller-actions] for more information.
+The +index+ (and other collection actions) will load the @projects 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.
-
-=== 3. Handle Unauthorized Access
-
-If the user authorization fails, a CanCan::Unauthorized exception will be raised. You can catch this and modify its behavior in the +ApplicationController+.
-
- class ApplicationController < ActionController::Base
- rescue_from CanCan::Unauthorized do |exception|
- redirect_to root_url, :alert => exception.message
- end
+ def index
+ @projects = @projects.where(:hidden => false)
end
-See {Exception Handling}[https://github.com/ryanb/cancan/wiki/exception-handling] for more information.
+You can check permissions on instances using the can? 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.
-=== 4. Lock It Down
+== Resource Attributes
-If you want to ensure authorization happens on every action in your application, add +check_authorization+ to your ApplicationController.
+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+.
- class ApplicationController < ActionController::Base
- check_authorization
- end
+ can :update, :projects, [:name, :priority]
-This will raise an exception if authorization is not performed in an action. If you want to skip this add +skip_authorization_check+ to a controller subclass. See {Ensure Authorization}[https://github.com/ryanb/cancan/wiki/Ensure-Authorization] for more information.
+If you use this in combination with +load_and_authorize_resource+ it will ensure that only those two attributes exist in params[:project] 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.
-== Wiki Docs
+ can :update, :products
+ cannot :update, :products, :price, :discontinued => true
-* {Upgrading to 1.6}[https://github.com/ryanb/cancan/wiki/Upgrading-to-1.6]
-* {Defining Abilities}[https://github.com/ryanb/cancan/wiki/Defining-Abilities]
-* {Checking Abilities}[https://github.com/ryanb/cancan/wiki/Checking-Abilities]
-* {Authorizing Controller Actions}[https://github.com/ryanb/cancan/wiki/Authorizing-Controller-Actions]
-* {Exception Handling}[https://github.com/ryanb/cancan/wiki/Exception-Handling]
-* {Changing Defaults}[https://github.com/ryanb/cancan/wiki/Changing-Defaults]
-* {See more}[https://github.com/ryanb/cancan/wiki]
+You can check permissions on specific attributes to determine what to show in the form.
+ <%= f.text_field :name if can? :update, @project, :name %>
-== Questions or Problems?
-
-If you have any issues with CanCan which you cannot find the solution to in the documentation[https://github.com/ryanb/cancan/wiki], please add an {issue on GitHub}[https://github.com/ryanb/cancan/issues] or fork the project and send a pull request.
-
-To get the specs running you should call +bundle+ and then +rake+. See the {spec/README}[https://github.com/ryanb/cancan/blob/master/spec/README.rdoc] for more information.
-
-
-== Special Thanks
-
-CanCan was inspired by declarative_authorization[https://github.com/stffn/declarative_authorization/] and aegis[https://github.com/makandra/aegis]. Also many thanks to the CanCan contributors[https://github.com/ryanb/cancan/contributors]. See the CHANGELOG[https://github.com/ryanb/cancan/blob/master/CHANGELOG.rdoc] for the full list.
diff --git a/lib/cancan/ability.rb b/lib/cancan/ability.rb
index 9e825ba..2ec2a23 100644
--- a/lib/cancan/ability.rb
+++ b/lib/cancan/ability.rb
@@ -22,21 +22,12 @@ module CanCan
#
# You can also pass the class instead of an instance (if you don't have one handy).
#
- # can? :create, Project
+ # can? :create, :projects
#
# Nested resources can be passed through a hash, this way conditions which are
# dependent upon the association will work when using a class.
#
- # can? :create, @category => Project
- #
- # Any additional arguments will be passed into the "can" block definition. This
- # can be used to pass more information about the user's request for example.
- #
- # can? :create, Project, request.remote_ip
- #
- # can :create Project do |project, remote_ip|
- # # ...
- # end
+ # can? :create, @category => :projects
#
# Not only can you use the can? method in the controller and view (see ControllerAdditions),
# but you can also call it directly on an ability instance.
@@ -71,22 +62,22 @@ module CanCan
# Defines which abilities are allowed using two arguments. The first one is the action
# you're setting the permission for, the second one is the class of object you're setting it on.
#
- # can :update, Article
+ # can :update, :articles
#
# You can pass an array for either of these parameters to match any one.
# Here the user has the ability to update or destroy both articles and comments.
#
- # can [:update, :destroy], [Article, Comment]
+ # can [:update, :destroy], [:articles, :comments]
#
# You can pass :all to match any object and :access to match any action. Here are some examples.
#
# can :access, :all
# can :update, :all
- # can :access, Project
+ # can :access, :projects
#
# You can pass a hash of conditions as the third argument. Here the user can only see active projects which he owns.
#
- # can :read, Project, :active => true, :user_id => user.id
+ # can :read, :projects, :active => true, :user_id => user.id
#
# See ActiveRecordAdditions#accessible_by for how to use this in database queries. These conditions
# are also used for initial attributes when building a record in ControllerAdditions#load_resource.
@@ -94,7 +85,7 @@ module CanCan
# If the conditions hash does not give you enough control over defining abilities, you can use a block
# along with any Ruby code you want.
#
- # can :update, Project do |project|
+ # can :update, :projects do |project|
# project.groups.include?(user.group)
# end
#
@@ -102,22 +93,16 @@ module CanCan
# will be denied access. The downside to using a block is that it cannot be used to generate
# conditions for database queries.
#
- # You can pass custom objects into this "can" method, this is usually done with a symbol
- # and is useful if a class isn't available to define permissions on.
+ # IMPORTANT: Neither a hash of conditions or a block will be used when checking permission on a symbol.
#
- # can :read, :stats
- # can? :read, :stats # => true
- #
- # IMPORTANT: Neither a hash of conditions or a block will be used when checking permission on a class.
- #
- # can :update, Project, :priority => 3
- # can? :update, Project # => true
+ # can :update, :projects, :priority => 3
+ # can? :update, :projects # => true
#
# If you pass no arguments to +can+, the action, class, and object will be passed to the block and the
# block will always be executed. This allows you to override the full behavior if the permissions are
# defined in an external source such as the database.
#
- # can do |action, object_class, object|
+ # can do |action, subject, object|
# # check the database and return true/false
# end
#
@@ -133,7 +118,7 @@ module CanCan
# A block can be passed just like "can", however if the logic is complex it is recommended
# to use the "can" method.
#
- # cannot :read, Product do |product|
+ # cannot :read, :projects do |product|
# product.invisible?
# end
#
@@ -144,19 +129,19 @@ module CanCan
# Alias one or more actions into another one.
#
# alias_action :update, :destroy, :to => :modify
- # can :modify, Comment
+ # can :modify, :comments
#
# Then :modify permission will apply to both :update and :destroy requests.
#
- # can? :update, Comment # => true
- # can? :destroy, Comment # => true
+ # can? :update, :comments # => true
+ # can? :destroy, :comments # => true
#
# This only works in one direction. Passing the aliased action into the "can?" call
# will not work because aliases are meant to generate more generic actions.
#
# alias_action :update, :destroy, :to => :modify
- # can :update, Comment
- # can? :modify, Comment # => false
+ # can :update, :comments
+ # can? :modify, :comments # => false
#
# The following aliases are added by default for conveniently mapping common controller actions.
#
diff --git a/lib/generators/cancan/ability/templates/ability.rb b/lib/generators/cancan/ability/templates/ability.rb
index 58929d7..306e78d 100644
--- a/lib/generators/cancan/ability/templates/ability.rb
+++ b/lib/generators/cancan/ability/templates/ability.rb
@@ -2,26 +2,22 @@ class Ability
include CanCan::Ability
def initialize(user)
- # Define abilities for the passed in user here. For example:
+ # Define abilities for the passed in (current) user. For example:
#
- # user ||= User.new # guest user (not logged in)
- # if user.admin?
- # can :manage, :all
+ # if user
+ # can :access, :all
# else
- # can :read, :all
+ # can :access, :home
+ # can :create, [:users, :sessions]
# end
#
- # The first argument to `can` is the action you are giving the user permission to do.
- # If you pass :manage it will apply to every action. Other common actions here are
- # :read, :create, :update and :destroy.
+ # 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 second argument is the resource the user can perform the action on. If you pass
- # :all it will apply to every resource. Otherwise pass a Ruby class of the resource.
- #
- # The third argument is an optional hash of conditions to further filter the objects.
- # For example, here the user can only update published articles.
- #
- # can :update, Article, :published => true
+ # 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 :access and :all
+ # to represent any action and controller respectively. Passing an array to either of
+ # these will grant permission on each item in the array.
#
# See the wiki for details: https://github.com/ryanb/cancan/wiki/Defining-Abilities
end