corntrace-cancan 1.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/CHANGELOG.rdoc +291 -0
  2. data/Gemfile +20 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +111 -0
  5. data/Rakefile +18 -0
  6. data/init.rb +1 -0
  7. data/lib/cancan.rb +13 -0
  8. data/lib/cancan/ability.rb +298 -0
  9. data/lib/cancan/controller_additions.rb +389 -0
  10. data/lib/cancan/controller_resource.rb +224 -0
  11. data/lib/cancan/exceptions.rb +50 -0
  12. data/lib/cancan/inherited_resource.rb +19 -0
  13. data/lib/cancan/matchers.rb +14 -0
  14. data/lib/cancan/model_adapters/abstract_adapter.rb +56 -0
  15. data/lib/cancan/model_adapters/active_record_adapter.rb +165 -0
  16. data/lib/cancan/model_adapters/data_mapper_adapter.rb +34 -0
  17. data/lib/cancan/model_adapters/default_adapter.rb +7 -0
  18. data/lib/cancan/model_adapters/mongoid_adapter.rb +53 -0
  19. data/lib/cancan/model_additions.rb +31 -0
  20. data/lib/cancan/rule.rb +142 -0
  21. data/lib/generators/cancan/ability/USAGE +4 -0
  22. data/lib/generators/cancan/ability/ability_generator.rb +11 -0
  23. data/lib/generators/cancan/ability/templates/ability.rb +28 -0
  24. data/spec/README.rdoc +28 -0
  25. data/spec/cancan/ability_spec.rb +419 -0
  26. data/spec/cancan/controller_additions_spec.rb +137 -0
  27. data/spec/cancan/controller_resource_spec.rb +412 -0
  28. data/spec/cancan/exceptions_spec.rb +58 -0
  29. data/spec/cancan/inherited_resource_spec.rb +42 -0
  30. data/spec/cancan/matchers_spec.rb +33 -0
  31. data/spec/cancan/model_adapters/active_record_adapter_spec.rb +278 -0
  32. data/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +119 -0
  33. data/spec/cancan/model_adapters/default_adapter_spec.rb +7 -0
  34. data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +216 -0
  35. data/spec/cancan/rule_spec.rb +39 -0
  36. data/spec/matchers.rb +13 -0
  37. data/spec/spec.opts +2 -0
  38. data/spec/spec_helper.rb +41 -0
  39. metadata +137 -0
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'cancan'
@@ -0,0 +1,13 @@
1
+ require 'cancan/ability'
2
+ require 'cancan/rule'
3
+ require 'cancan/controller_resource'
4
+ require 'cancan/controller_additions'
5
+ require 'cancan/model_additions'
6
+ require 'cancan/exceptions'
7
+ require 'cancan/inherited_resource'
8
+
9
+ require 'cancan/model_adapters/abstract_adapter'
10
+ require 'cancan/model_adapters/default_adapter'
11
+ require 'cancan/model_adapters/active_record_adapter' if defined? ActiveRecord
12
+ require 'cancan/model_adapters/data_mapper_adapter' if defined? DataMapper
13
+ require 'cancan/model_adapters/mongoid_adapter' if defined?(Mongoid) && defined?(Mongoid::Document)
@@ -0,0 +1,298 @@
1
+ module CanCan
2
+
3
+ # This module is designed to be included into an Ability class. This will
4
+ # provide the "can" methods for defining and checking abilities.
5
+ #
6
+ # class Ability
7
+ # include CanCan::Ability
8
+ #
9
+ # def initialize(user)
10
+ # if user.admin?
11
+ # can :manage, :all
12
+ # else
13
+ # can :read, :all
14
+ # end
15
+ # end
16
+ # end
17
+ #
18
+ module Ability
19
+ # Check if the user has permission to perform a given action on an object.
20
+ #
21
+ # can? :destroy, @project
22
+ #
23
+ # You can also pass the class instead of an instance (if you don't have one handy).
24
+ #
25
+ # can? :create, Project
26
+ #
27
+ # Nested resources can be passed through a hash, this way conditions which are
28
+ # dependent upon the association will work when using a class.
29
+ #
30
+ # can? :create, @category => Project
31
+ #
32
+ # Any additional arguments will be passed into the "can" block definition. This
33
+ # can be used to pass more information about the user's request for example.
34
+ #
35
+ # can? :create, Project, request.remote_ip
36
+ #
37
+ # can :create Project do |project, remote_ip|
38
+ # # ...
39
+ # end
40
+ #
41
+ # Not only can you use the can? method in the controller and view (see ControllerAdditions),
42
+ # but you can also call it directly on an ability instance.
43
+ #
44
+ # ability.can? :destroy, @project
45
+ #
46
+ # This makes testing a user's abilities very easy.
47
+ #
48
+ # def test "user can only destroy projects which he owns"
49
+ # user = User.new
50
+ # ability = Ability.new(user)
51
+ # assert ability.can?(:destroy, Project.new(:user => user))
52
+ # assert ability.cannot?(:destroy, Project.new)
53
+ # end
54
+ #
55
+ # Also see the RSpec Matchers to aid in testing.
56
+ def can?(action, subject, *extra_args)
57
+ match = relevant_rules_for_match(action, subject).detect do |rule|
58
+ rule.matches_conditions?(action, subject, extra_args)
59
+ end
60
+ match ? match.base_behavior : false
61
+ end
62
+
63
+ # Convenience method which works the same as "can?" but returns the opposite value.
64
+ #
65
+ # cannot? :destroy, @project
66
+ #
67
+ def cannot?(*args)
68
+ !can?(*args)
69
+ end
70
+
71
+ # Defines which abilities are allowed using two arguments. The first one is the action
72
+ # you're setting the permission for, the second one is the class of object you're setting it on.
73
+ #
74
+ # can :update, Article
75
+ #
76
+ # You can pass an array for either of these parameters to match any one.
77
+ # Here the user has the ability to update or destroy both articles and comments.
78
+ #
79
+ # can [:update, :destroy], [Article, Comment]
80
+ #
81
+ # You can pass :all to match any object and :manage to match any action. Here are some examples.
82
+ #
83
+ # can :manage, :all
84
+ # can :update, :all
85
+ # can :manage, Project
86
+ #
87
+ # You can pass a hash of conditions as the third argument. Here the user can only see active projects which he owns.
88
+ #
89
+ # can :read, Project, :active => true, :user_id => user.id
90
+ #
91
+ # See ActiveRecordAdditions#accessible_by for how to use this in database queries. These conditions
92
+ # are also used for initial attributes when building a record in ControllerAdditions#load_resource.
93
+ #
94
+ # If the conditions hash does not give you enough control over defining abilities, you can use a block
95
+ # along with any Ruby code you want.
96
+ #
97
+ # can :update, Project do |project|
98
+ # project.groups.include?(user.group)
99
+ # end
100
+ #
101
+ # If the block returns true then the user has that :update ability for that project, otherwise he
102
+ # will be denied access. The downside to using a block is that it cannot be used to generate
103
+ # conditions for database queries.
104
+ #
105
+ # You can pass custom objects into this "can" method, this is usually done with a symbol
106
+ # and is useful if a class isn't available to define permissions on.
107
+ #
108
+ # can :read, :stats
109
+ # can? :read, :stats # => true
110
+ #
111
+ # IMPORTANT: Neither a hash of conditions or a block will be used when checking permission on a class.
112
+ #
113
+ # can :update, Project, :priority => 3
114
+ # can? :update, Project # => true
115
+ #
116
+ # If you pass no arguments to +can+, the action, class, and object will be passed to the block and the
117
+ # block will always be executed. This allows you to override the full behavior if the permissions are
118
+ # defined in an external source such as the database.
119
+ #
120
+ # can do |action, object_class, object|
121
+ # # check the database and return true/false
122
+ # end
123
+ #
124
+ def can(action = nil, subject = nil, conditions = nil, &block)
125
+ rules << Rule.new(true, action, subject, conditions, block)
126
+ end
127
+
128
+ # Defines an ability which cannot be done. Accepts the same arguments as "can".
129
+ #
130
+ # can :read, :all
131
+ # cannot :read, Comment
132
+ #
133
+ # A block can be passed just like "can", however if the logic is complex it is recommended
134
+ # to use the "can" method.
135
+ #
136
+ # cannot :read, Product do |product|
137
+ # product.invisible?
138
+ # end
139
+ #
140
+ def cannot(action = nil, subject = nil, conditions = nil, &block)
141
+ rules << Rule.new(false, action, subject, conditions, block)
142
+ end
143
+
144
+ # Alias one or more actions into another one.
145
+ #
146
+ # alias_action :update, :destroy, :to => :modify
147
+ # can :modify, Comment
148
+ #
149
+ # Then :modify permission will apply to both :update and :destroy requests.
150
+ #
151
+ # can? :update, Comment # => true
152
+ # can? :destroy, Comment # => true
153
+ #
154
+ # This only works in one direction. Passing the aliased action into the "can?" call
155
+ # will not work because aliases are meant to generate more generic actions.
156
+ #
157
+ # alias_action :update, :destroy, :to => :modify
158
+ # can :update, Comment
159
+ # can? :modify, Comment # => false
160
+ #
161
+ # Unless that exact alias is used.
162
+ #
163
+ # can :modify, Comment
164
+ # can? :modify, Comment # => true
165
+ #
166
+ # The following aliases are added by default for conveniently mapping common controller actions.
167
+ #
168
+ # alias_action :index, :show, :to => :read
169
+ # alias_action :new, :to => :create
170
+ # alias_action :edit, :to => :update
171
+ #
172
+ # This way one can use params[:action] in the controller to determine the permission.
173
+ def alias_action(*args)
174
+ target = args.pop[:to]
175
+ aliased_actions[target] ||= []
176
+ aliased_actions[target] += args
177
+ end
178
+
179
+ # Returns a hash of aliased actions. The key is the target and the value is an array of actions aliasing the key.
180
+ def aliased_actions
181
+ @aliased_actions ||= default_alias_actions
182
+ end
183
+
184
+ # Removes previously aliased actions including the defaults.
185
+ def clear_aliased_actions
186
+ @aliased_actions = {}
187
+ end
188
+
189
+ def model_adapter(model_class, action)
190
+ adapter_class = ModelAdapters::AbstractAdapter.adapter_class(model_class)
191
+ adapter_class.new(model_class, relevant_rules_for_query(action, model_class))
192
+ end
193
+
194
+ # See ControllerAdditions#authorize! for documentation.
195
+ def authorize!(action, subject, *args)
196
+ message = nil
197
+ if args.last.kind_of?(Hash) && args.last.has_key?(:message)
198
+ message = args.pop[:message]
199
+ end
200
+ if cannot?(action, subject, *args)
201
+ message ||= unauthorized_message(action, subject)
202
+ raise AccessDenied.new(message, action, subject)
203
+ end
204
+ subject
205
+ end
206
+
207
+ def unauthorized_message(action, subject)
208
+ keys = unauthorized_message_keys(action, subject)
209
+ variables = {:action => action.to_s}
210
+ variables[:subject] = (subject.class == Class ? subject : subject.class).to_s.underscore.humanize.downcase
211
+ message = I18n.translate(nil, variables.merge(:scope => :unauthorized, :default => keys + [""]))
212
+ message.blank? ? nil : message
213
+ end
214
+
215
+ def attributes_for(action, subject)
216
+ attributes = {}
217
+ relevant_rules(action, subject).map do |rule|
218
+ attributes.merge!(rule.attributes_from_conditions) if rule.base_behavior
219
+ end
220
+ attributes
221
+ end
222
+
223
+ def has_block?(action, subject)
224
+ relevant_rules(action, subject).any?(&:only_block?)
225
+ end
226
+
227
+ def has_raw_sql?(action, subject)
228
+ relevant_rules(action, subject).any?(&:only_raw_sql?)
229
+ end
230
+
231
+ private
232
+
233
+ def unauthorized_message_keys(action, subject)
234
+ subject = (subject.class == Class ? subject : subject.class).name.underscore unless subject.kind_of? Symbol
235
+ [subject, :all].map do |try_subject|
236
+ [aliases_for_action(action), :manage].flatten.map do |try_action|
237
+ :"#{try_action}.#{try_subject}"
238
+ end
239
+ end.flatten
240
+ end
241
+
242
+ # Accepts an array of actions and returns an array of actions which match.
243
+ # This should be called before "matches?" and other checking methods since they
244
+ # rely on the actions to be expanded.
245
+ def expand_actions(actions)
246
+ actions.map do |action|
247
+ aliased_actions[action] ? [action, *expand_actions(aliased_actions[action])] : action
248
+ end.flatten
249
+ end
250
+
251
+ # Given an action, it will try to find all of the actions which are aliased to it.
252
+ # This does the opposite kind of lookup as expand_actions.
253
+ def aliases_for_action(action)
254
+ results = [action]
255
+ aliased_actions.each do |aliased_action, actions|
256
+ results += aliases_for_action(aliased_action) if actions.include? action
257
+ end
258
+ results
259
+ end
260
+
261
+ def rules
262
+ @rules ||= []
263
+ end
264
+
265
+ # Returns an array of Rule instances which match the action and subject
266
+ # This does not take into consideration any hash conditions or block statements
267
+ def relevant_rules(action, subject)
268
+ rules.reverse.select do |rule|
269
+ rule.expanded_actions = expand_actions(rule.actions)
270
+ rule.relevant? action, subject
271
+ end
272
+ end
273
+
274
+ def relevant_rules_for_match(action, subject)
275
+ relevant_rules(action, subject).each do |rule|
276
+ if rule.only_raw_sql?
277
+ raise Error, "The can? and cannot? call cannot be used with a raw sql 'can' definition. The checking code cannot be determined for #{action.inspect} #{subject.inspect}"
278
+ end
279
+ end
280
+ end
281
+
282
+ def relevant_rules_for_query(action, subject)
283
+ relevant_rules(action, subject).each do |rule|
284
+ if rule.only_block?
285
+ raise Error, "The accessible_by call cannot be used with a block 'can' definition. The SQL cannot be determined for #{action.inspect} #{subject.inspect}"
286
+ end
287
+ end
288
+ end
289
+
290
+ def default_alias_actions
291
+ {
292
+ :read => [:index, :show],
293
+ :create => [:new],
294
+ :update => [:edit],
295
+ }
296
+ end
297
+ end
298
+ end
@@ -0,0 +1,389 @@
1
+ module CanCan
2
+
3
+ # This module is automatically included into all controllers.
4
+ # It also makes the "can?" and "cannot?" methods available to all views.
5
+ module ControllerAdditions
6
+ module ClassMethods
7
+ # Sets up a before filter which loads and authorizes the current resource. This performs both
8
+ # load_resource and authorize_resource and accepts the same arguments. See those methods for details.
9
+ #
10
+ # class BooksController < ApplicationController
11
+ # load_and_authorize_resource
12
+ # end
13
+ #
14
+ def load_and_authorize_resource(*args)
15
+ cancan_resource_class.add_before_filter(self, :load_and_authorize_resource, *args)
16
+ end
17
+
18
+ # Sets up a before filter which loads the model resource into an instance variable.
19
+ # For example, given an ArticlesController it will load the current article into the @article
20
+ # instance variable. It does this by either calling Article.find(params[:id]) or
21
+ # Article.new(params[:article]) depending upon the action. The index action will
22
+ # automatically set @articles to Article.accessible_by(current_ability).
23
+ #
24
+ # If a conditions hash is used in the Ability, the +new+ and +create+ actions will set
25
+ # the initial attributes based on these conditions. This way these actions will satisfy
26
+ # the ability restrictions.
27
+ #
28
+ # Call this method directly on the controller class.
29
+ #
30
+ # class BooksController < ApplicationController
31
+ # load_resource
32
+ # end
33
+ #
34
+ # A resource is not loaded if the instance variable is already set. This makes it easy to override
35
+ # the behavior through a before_filter on certain actions.
36
+ #
37
+ # class BooksController < ApplicationController
38
+ # before_filter :find_book_by_permalink, :only => :show
39
+ # load_resource
40
+ #
41
+ # private
42
+ #
43
+ # def find_book_by_permalink
44
+ # @book = Book.find_by_permalink!(params[:id)
45
+ # end
46
+ # end
47
+ #
48
+ # If a name is provided which does not match the controller it assumes it is a parent resource. Child
49
+ # resources can then be loaded through it.
50
+ #
51
+ # class BooksController < ApplicationController
52
+ # load_resource :author
53
+ # load_resource :book, :through => :author
54
+ # end
55
+ #
56
+ # Here the author resource will be loaded before each action using params[:author_id]. The book resource
57
+ # will then be loaded through the @author instance variable.
58
+ #
59
+ # That first argument is optional and will default to the singular name of the controller.
60
+ # A hash of options (see below) can also be passed to this method to further customize it.
61
+ #
62
+ # See load_and_authorize_resource to automatically authorize the resource too.
63
+ #
64
+ # Options:
65
+ # [:+only+]
66
+ # Only applies before filter to given actions.
67
+ #
68
+ # [:+except+]
69
+ # Does not apply before filter to given actions.
70
+ #
71
+ # [:+through+]
72
+ # Load this resource through another one. This should match the name of the parent instance variable or method.
73
+ #
74
+ # [:+through_association+]
75
+ # The name of the association to fetch the child records through the parent resource. This is normally not needed
76
+ # because it defaults to the pluralized resource name.
77
+ #
78
+ # [:+shallow+]
79
+ # Pass +true+ to allow this resource to be loaded directly when parent is +nil+. Defaults to +false+.
80
+ #
81
+ # [:+singleton+]
82
+ # Pass +true+ if this is a singleton resource through a +has_one+ association.
83
+ #
84
+ # [:+parent+]
85
+ # True or false depending on if the resource is considered a parent resource. This defaults to +true+ if a resource
86
+ # name is given which does not match the controller.
87
+ #
88
+ # [:+class+]
89
+ # The class to use for the model (string or constant).
90
+ #
91
+ # [:+instance_name+]
92
+ # The name of the instance variable to load the resource into.
93
+ #
94
+ # [:+find_by+]
95
+ # Find using a different attribute other than id. For example.
96
+ #
97
+ # load_resource :find_by => :permalink # will use find_by_permlink!(params[:id])
98
+ #
99
+ # [:+collection+]
100
+ # Specify which actions are resource collection actions in addition to :+index+. This
101
+ # is usually not necessary because it will try to guess depending on if the id param is present.
102
+ #
103
+ # load_resource :collection => [:sort, :list]
104
+ #
105
+ # [:+new+]
106
+ # Specify which actions are new resource actions in addition to :+new+ and :+create+.
107
+ # Pass an action name into here if you would like to build a new resource instead of
108
+ # fetch one.
109
+ #
110
+ # load_resource :new => :build
111
+ #
112
+ # [:+prepend+]
113
+ # Passing +true+ will use prepend_before_filter instead of a normal before_filter.
114
+ #
115
+ def load_resource(*args)
116
+ cancan_resource_class.add_before_filter(self, :load_resource, *args)
117
+ end
118
+
119
+ # Sets up a before filter which authorizes the resource using the instance variable.
120
+ # For example, if you have an ArticlesController it will check the @article instance variable
121
+ # and ensure the user can perform the current action on it. Under the hood it is doing
122
+ # something like the following.
123
+ #
124
+ # authorize!(params[:action].to_sym, @article || Article)
125
+ #
126
+ # Call this method directly on the controller class.
127
+ #
128
+ # class BooksController < ApplicationController
129
+ # authorize_resource
130
+ # end
131
+ #
132
+ # If you pass in the name of a resource which does not match the controller it will assume
133
+ # it is a parent resource.
134
+ #
135
+ # class BooksController < ApplicationController
136
+ # authorize_resource :author
137
+ # authorize_resource :book
138
+ # end
139
+ #
140
+ # Here it will authorize :+show+, @+author+ on every action before authorizing the book.
141
+ #
142
+ # That first argument is optional and will default to the singular name of the controller.
143
+ # A hash of options (see below) can also be passed to this method to further customize it.
144
+ #
145
+ # See load_and_authorize_resource to automatically load the resource too.
146
+ #
147
+ # Options:
148
+ # [:+only+]
149
+ # Only applies before filter to given actions.
150
+ #
151
+ # [:+except+]
152
+ # Does not apply before filter to given actions.
153
+ #
154
+ # [:+parent+]
155
+ # True or false depending on if the resource is considered a parent resource. This defaults to +true+ if a resource
156
+ # name is given which does not match the controller.
157
+ #
158
+ # [:+class+]
159
+ # The class to use for the model (string or constant). This passed in when the instance variable is not set.
160
+ # Pass +false+ if there is no associated class for this resource and it will use a symbol of the resource name.
161
+ #
162
+ # [:+instance_name+]
163
+ # The name of the instance variable for this resource.
164
+ #
165
+ # [:+through+]
166
+ # Authorize conditions on this parent resource when instance isn't available.
167
+ #
168
+ # [:+prepend+]
169
+ # Passing +true+ will use prepend_before_filter instead of a normal before_filter.
170
+ #
171
+ def authorize_resource(*args)
172
+ cancan_resource_class.add_before_filter(self, :authorize_resource, *args)
173
+ end
174
+
175
+ # Skip both the loading and authorization behavior of CanCan for this given controller. This is primarily
176
+ # useful to skip the behavior of a superclass. You can pass :only and :except options to specify which actions
177
+ # to skip the effects on. It will apply to all actions by default.
178
+ #
179
+ # class ProjectsController < SomeOtherController
180
+ # skip_load_and_authorize_resource :only => :index
181
+ # end
182
+ #
183
+ # You can also pass the resource name as the first argument to skip that resource.
184
+ def skip_load_and_authorize_resource(*args)
185
+ skip_load_resource(*args)
186
+ skip_authorize_resource(*args)
187
+ end
188
+
189
+ # Skip both the loading behavior of CanCan. This is useful when using +load_and_authorize_resource+ but want to
190
+ # only do authorization on certain actions. You can pass :only and :except options to specify which actions to
191
+ # skip the effects on. It will apply to all actions by default.
192
+ #
193
+ # class ProjectsController < ApplicationController
194
+ # load_and_authorize_resource
195
+ # skip_load_resource :only => :index
196
+ # end
197
+ #
198
+ # You can also pass the resource name as the first argument to skip that resource.
199
+ def skip_load_resource(*args)
200
+ options = args.extract_options!
201
+ name = args.first
202
+ cancan_skipper[:load][name] = options
203
+ end
204
+
205
+ # Skip both the authorization behavior of CanCan. This is useful when using +load_and_authorize_resource+ but want to
206
+ # only do loading on certain actions. You can pass :only and :except options to specify which actions to
207
+ # skip the effects on. It will apply to all actions by default.
208
+ #
209
+ # class ProjectsController < ApplicationController
210
+ # load_and_authorize_resource
211
+ # skip_authorize_resource :only => :index
212
+ # end
213
+ #
214
+ # You can also pass the resource name as the first argument to skip that resource.
215
+ def skip_authorize_resource(*args)
216
+ options = args.extract_options!
217
+ name = args.first
218
+ cancan_skipper[:authorize][name] = options
219
+ end
220
+
221
+ # Add this to a controller to ensure it performs authorization through +authorized+! or +authorize_resource+ call.
222
+ # If neither of these authorization methods are called, a CanCan::AuthorizationNotPerformed exception will be raised.
223
+ # This is normally added to the ApplicationController to ensure all controller actions do authorization.
224
+ #
225
+ # class ApplicationController < ActionController::Base
226
+ # check_authorization
227
+ # end
228
+ #
229
+ # See skip_authorization_check to bypass this check on specific controller actions.
230
+ #
231
+ # Options:
232
+ # [:+only+]
233
+ # Only applies to given actions.
234
+ #
235
+ # [:+except+]
236
+ # Does not apply to given actions.
237
+ #
238
+ # [:+if+]
239
+ # Supply the name of a controller method to be called. The authorization check only takes place if this returns true.
240
+ #
241
+ # check_authorization :if => :admin_controller?
242
+ #
243
+ # [:+unless+]
244
+ # Supply the name of a controller method to be called. The authorization check only takes place if this returns false.
245
+ #
246
+ # check_authorization :unless => :devise_controller?
247
+ #
248
+ def check_authorization(options = {})
249
+ self.after_filter(options.slice(:only, :except)) do |controller|
250
+ return if controller.instance_variable_defined?(:@_authorized)
251
+ return if options[:if] && !controller.send(options[:if])
252
+ return if options[:unless] && controller.send(options[:unless])
253
+ raise AuthorizationNotPerformed, "This action failed the check_authorization because it does not authorize_resource. Add skip_authorization_check to bypass this check."
254
+ end
255
+ end
256
+
257
+ # Call this in the class of a controller to skip the check_authorization behavior on the actions.
258
+ #
259
+ # class HomeController < ApplicationController
260
+ # skip_authorization_check :only => :index
261
+ # end
262
+ #
263
+ # Any arguments are passed to the +before_filter+ it triggers.
264
+ def skip_authorization_check(*args)
265
+ self.before_filter(*args) do |controller|
266
+ controller.instance_variable_set(:@_authorized, true)
267
+ end
268
+ end
269
+
270
+ def skip_authorization(*args)
271
+ raise ImplementationRemoved, "The CanCan skip_authorization method has been renamed to skip_authorization_check. Please update your code."
272
+ end
273
+
274
+ def cancan_resource_class
275
+ if ancestors.map(&:to_s).include? "InheritedResources::Actions"
276
+ InheritedResource
277
+ else
278
+ ControllerResource
279
+ end
280
+ end
281
+
282
+ def cancan_skipper
283
+ @_cancan_skipper ||= {:authorize => {}, :load => {}}
284
+ end
285
+ end
286
+
287
+ def self.included(base)
288
+ base.extend ClassMethods
289
+ base.helper_method :can?, :cannot?, :current_ability
290
+ end
291
+
292
+ # Raises a CanCan::AccessDenied exception if the current_ability cannot
293
+ # perform the given action. This is usually called in a controller action or
294
+ # before filter to perform the authorization.
295
+ #
296
+ # def show
297
+ # @article = Article.find(params[:id])
298
+ # authorize! :read, @article
299
+ # end
300
+ #
301
+ # A :message option can be passed to specify a different message.
302
+ #
303
+ # authorize! :read, @article, :message => "Not authorized to read #{@article.name}"
304
+ #
305
+ # You can also use I18n to customize the message. Action aliases defined in Ability work here.
306
+ #
307
+ # en:
308
+ # unauthorized:
309
+ # manage:
310
+ # all: "Not authorized to %{action} %{subject}."
311
+ # user: "Not allowed to manage other user accounts."
312
+ # update:
313
+ # project: "Not allowed to update this project."
314
+ #
315
+ # You can rescue from the exception in the controller to customize how unauthorized
316
+ # access is displayed to the user.
317
+ #
318
+ # class ApplicationController < ActionController::Base
319
+ # rescue_from CanCan::AccessDenied do |exception|
320
+ # redirect_to root_url, :alert => exception.message
321
+ # end
322
+ # end
323
+ #
324
+ # See the CanCan::AccessDenied exception for more details on working with the exception.
325
+ #
326
+ # See the load_and_authorize_resource method to automatically add the authorize! behavior
327
+ # to the default RESTful actions.
328
+ def authorize!(*args)
329
+ @_authorized = true
330
+ current_ability.authorize!(*args)
331
+ end
332
+
333
+ def unauthorized!(message = nil)
334
+ raise ImplementationRemoved, "The unauthorized! method has been removed from CanCan, use authorize! instead."
335
+ end
336
+
337
+ # Creates and returns the current user's ability and caches it. If you
338
+ # want to override how the Ability is defined then this is the place.
339
+ # Just define the method in the controller to change behavior.
340
+ #
341
+ # def current_ability
342
+ # # instead of Ability.new(current_user)
343
+ # @current_ability ||= UserAbility.new(current_account)
344
+ # end
345
+ #
346
+ # Notice it is important to cache the ability object so it is not
347
+ # recreated every time.
348
+ def current_ability
349
+ @current_ability ||= ::Ability.new(current_user)
350
+ end
351
+
352
+ # Use in the controller or view to check the user's permission for a given action
353
+ # and object.
354
+ #
355
+ # can? :destroy, @project
356
+ #
357
+ # You can also pass the class instead of an instance (if you don't have one handy).
358
+ #
359
+ # <% if can? :create, Project %>
360
+ # <%= link_to "New Project", new_project_path %>
361
+ # <% end %>
362
+ #
363
+ # If it's a nested resource, you can pass the parent instance in a hash. This way it will
364
+ # check conditions which reach through that association.
365
+ #
366
+ # <% if can? :create, @category => Project %>
367
+ # <%= link_to "New Project", new_project_path %>
368
+ # <% end %>
369
+ #
370
+ # This simply calls "can?" on the current_ability. See Ability#can?.
371
+ def can?(*args)
372
+ current_ability.can?(*args)
373
+ end
374
+
375
+ # Convenience method which works the same as "can?" but returns the opposite value.
376
+ #
377
+ # cannot? :destroy, @project
378
+ #
379
+ def cannot?(*args)
380
+ current_ability.cannot?(*args)
381
+ end
382
+ end
383
+ end
384
+
385
+ if defined? ActionController
386
+ ActionController::Base.class_eval do
387
+ include CanCan::ControllerAdditions
388
+ end
389
+ end