codeprimate-cancan 1.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +222 -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 +167 -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 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 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
+ next if controller.instance_variable_defined?(:@_authorized)
251
+ next if options[:if] && !controller.send(options[:if])
252
+ next 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