Skip to content
This repository
Newer
Older
100644 184 lines (110 sloc) 6.065 kb
6c6a57be »
2009-11-16 adding documentation placeholder
1 = CanCan
2
4322da9d »
2009-11-17 expanding readme documentation
3 This is a simple authorization solution for Ruby on Rails to restrict what a given user is allowed to access in the application. This is completely decoupled from any role based implementation allowing you to define user roles the way you want. All permissions are stored in a single location for convenience.
b1d3d66e »
2009-11-16 filling readme
4
4322da9d »
2009-11-17 expanding readme documentation
5 This assumes you already have authentication (such as Authlogic[http://github.com/binarylogic/authlogic]) which provides a current_user model.
b1d3d66e »
2009-11-16 filling readme
6
0ae41f57 »
2009-11-18 mentioning wiki in readme
7 See the RDocs[http://rdoc.info/projects/ryanb/cancan] and Wiki[http://wiki.github.com/ryanb/cancan] for additional documentation.
b1d3d66e »
2009-11-16 filling readme
8
9 == Installation
10
28eaf1bc »
2009-11-16 releasing gem v0.1.0
11 You can set it up as a gem in your environment.rb file.
12
13 config.gem "cancan", :source => "http://gemcutter.org"
14
15 And then install the gem.
b1d3d66e »
2009-11-16 filling readme
16
9d582265 »
2009-11-16 couple fixes in readme
17 sudo rake gems:install
b1d3d66e »
2009-11-16 filling readme
18
28eaf1bc »
2009-11-16 releasing gem v0.1.0
19 Alternatively you can install it as a Rails plugin.
20
21 script/plugin install git://github.com/ryanb/cancan.git
b1d3d66e »
2009-11-16 filling readme
22
23
24 == Setup
25
4322da9d »
2009-11-17 expanding readme documentation
26 First, define a class called Ability in "models/ability.rb".
b1d3d66e »
2009-11-16 filling readme
27
28 class Ability
29 include CanCan::Ability
30
1edf5831 »
2009-11-17 BACKWARDS INCOMPATIBLE: use Ability#initialize instead of 'prepare' t…
31 def initialize(user)
b1d3d66e »
2009-11-16 filling readme
32 if user.admin?
33 can :manage, :all
34 else
35 can :read, :all
36 end
37 end
38 end
39
4322da9d »
2009-11-17 expanding readme documentation
40 This is where all permissions will go. See the "Defining Abilities" section below for more information.
b1d3d66e »
2009-11-16 filling readme
41
4322da9d »
2009-11-17 expanding readme documentation
42 You can access the current permissions at any point using the "can?" and "cannot?" methods in the view.
b1d3d66e »
2009-11-16 filling readme
43
44 <% if can? :update, @article %>
45 <%= link_to "Edit", edit_article_path(@article) %>
46 <% end %>
47
4322da9d »
2009-11-17 expanding readme documentation
48 You can also use these methods in a controller along with the "unauthorized!" method to restrict access.
b1d3d66e »
2009-11-16 filling readme
49
50 def show
51 @article = Article.find(params[:id])
0f49b547 »
2009-11-17 adding 'cannot?' method which performs opposite check of 'can?' - clo…
52 unauthorized! if cannot? :read, @article
b1d3d66e »
2009-11-16 filling readme
53 end
54
4322da9d »
2009-11-17 expanding readme documentation
55 Setting this for every action can be tedious, therefore a before filter is also provided to automatically authorize all actions in a RESTful style resource controller.
b1d3d66e »
2009-11-16 filling readme
56
57 class ArticlesController < ApplicationController
58 before_filter :load_and_authorize_resource
59
60 def show
61 # @article is already loaded
62 end
63 end
64
4322da9d »
2009-11-17 expanding readme documentation
65 If the user authorization fails, a CanCan::AccessDenied exception will be raised. You can catch this and modify its behavior in the ApplicationController.
b1d3d66e »
2009-11-16 filling readme
66
67 class ApplicationController < ActionController::Base
68 rescue_from CanCan::AccessDenied, :with => :access_denied
69
70 protected
71
72 def access_denied
73 flash[:error] = "Sorry, you are not allowed to access that page."
74 redirect_to root_url
75 end
76 end
77
78
79 == Defining Abilities
80
4322da9d »
2009-11-17 expanding readme documentation
81 As shown above, the Ability class is where all user permissions are defined. The user model is passed into the initialize method so you are free to modify the permissions based on the user's attributes. This way CanCan is completely decoupled with how you choose to handle roles.
b1d3d66e »
2009-11-16 filling readme
82
83 The "can" method accepts 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.
84
85 can :update, Article
86
87 You can pass an array for either of these parameters to match any one.
88
89 can [:update, :destroy], [Article, Comment]
90
91 In this case the user has the ability to update or destroy both articles and comments.
92
4322da9d »
2009-11-17 expanding readme documentation
93 You can pass a block to provide logic based on the article's attributes.
b1d3d66e »
2009-11-16 filling readme
94
95 can :update, Article do |article|
96 article && article.user == user
97 end
98
99 If the block returns true then the user has that :update ability for that article, otherwise he will be denied access. It's possible for the passed in model to be nil if one isn't specified, so be sure to take that into consideration.
100
101 You can pass :all to reference every type of object. In this case the object type will be passed into the block as well (just in case object is nil).
102
103 can :read, :all do |object_class, object|
104 object_class != Order
105 end
106
107 Here the user has permission to read all objects except orders.
108
109 You can also pass :manage as the action which will match any action. In this case the action is passed to the block.
110
111 can :manage, Comment do |action, comment|
112 action != :destroy
113 end
d4405e60 »
2009-11-25 adding cannot method to define which abilities cannot be done - closes
114
115 Finally, the "cannot" method works similar to "can" but defines which abilities cannot be done.
b1d3d66e »
2009-11-16 filling readme
116
d4405e60 »
2009-11-25 adding cannot method to define which abilities cannot be done - closes
117 can :read, :all
118 cannot :read, Product
b1d3d66e »
2009-11-16 filling readme
119
120
121 == Checking Abilities
122
123 Use the "can?" method in the controller or view to check the user's permission for a given action and object.
124
125 can? :destroy, @project
126
4322da9d »
2009-11-17 expanding readme documentation
127 You can also pass the class instead of an instance (if you don't have one handy).
b1d3d66e »
2009-11-16 filling readme
128
129 <% if can? :create, Project %>
130 <%= link_to "New Project", new_project_path %>
131 <% end %>
132
0f49b547 »
2009-11-17 adding 'cannot?' method which performs opposite check of 'can?' - clo…
133 The "cannot?" method is for convenience and performs the opposite check of "can?"
134
135 cannot? :destroy, @project
136
b1d3d66e »
2009-11-16 filling readme
137
d4405e60 »
2009-11-25 adding cannot method to define which abilities cannot be done - closes
138 == Aliasing Actions
139
140 You can use the "alias_action" method to alias one or more actions into one.
141
142 alias_action :update, :destroy, :to => :modify
143 can :modify, Comment
144 can? :update, Comment # => true
145
146 The following aliases are added by default for conveniently mapping common controller actions.
147
148 alias_action :index, :show, :to => :read
149 alias_action :new, :to => :create
150 alias_action :edit, :to => :update
151
152
1edf5831 »
2009-11-17 BACKWARDS INCOMPATIBLE: use Ability#initialize instead of 'prepare' t…
153 == Assumptions & Configuring
b1d3d66e »
2009-11-16 filling readme
154
155 CanCan makes two assumptions about your application.
156
4322da9d »
2009-11-17 expanding readme documentation
157 * You have an Ability class which defines the permissions.
158 * You have a current_user method in the controller which returns the current user model.
b1d3d66e »
2009-11-16 filling readme
159
4322da9d »
2009-11-17 expanding readme documentation
160 You can override these by overriding the "current_ability" method in your ApplicationController.
b1d3d66e »
2009-11-16 filling readme
161
162 def current_ability
1edf5831 »
2009-11-17 BACKWARDS INCOMPATIBLE: use Ability#initialize instead of 'prepare' t…
163 UserAbility.new(current_account) # instead of Ability.new(current_user)
b1d3d66e »
2009-11-16 filling readme
164 end
165
166 That's it!
167
168
df276536 »
2009-11-17 adding documentation for testing abilities - closes #6
169 == Testing Abilities
170
171 It is very easy to test the Ability model since you can call "can?" directly on it as you would in the view or controller.
172
072cb0f2 »
2009-11-17 fixing spacing issues in README
173 def test "user can only destroy projects which he owns"
174 user = User.new
175 ability = Ability.new(user)
176 assert ability.can?(:destroy, Project.new(:user => user))
177 assert ability.cannot?(:destroy, Project.new)
178 end
df276536 »
2009-11-17 adding documentation for testing abilities - closes #6
179
180
9d582265 »
2009-11-16 couple fixes in readme
181 == Special Thanks
182
183 CanCan was inspired by declarative_authorization[http://github.com/stffn/declarative_authorization/] and aegis[http://github.com/makandra/aegis]. Many thanks to the authors and contributors.
Something went wrong with that request. Please try again.