cancancan 1.13.1 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +5 -5
  2. data/cancancan.gemspec +18 -18
  3. data/init.rb +2 -0
  4. data/lib/cancan.rb +9 -11
  5. data/lib/cancan/ability.rb +93 -194
  6. data/lib/cancan/ability/actions.rb +93 -0
  7. data/lib/cancan/ability/rules.rb +93 -0
  8. data/lib/cancan/ability/strong_parameter_support.rb +41 -0
  9. data/lib/cancan/conditions_matcher.rb +106 -0
  10. data/lib/cancan/controller_additions.rb +38 -41
  11. data/lib/cancan/controller_resource.rb +52 -211
  12. data/lib/cancan/controller_resource_builder.rb +26 -0
  13. data/lib/cancan/controller_resource_finder.rb +42 -0
  14. data/lib/cancan/controller_resource_loader.rb +120 -0
  15. data/lib/cancan/controller_resource_name_finder.rb +23 -0
  16. data/lib/cancan/controller_resource_sanitizer.rb +32 -0
  17. data/lib/cancan/exceptions.rb +17 -5
  18. data/lib/cancan/matchers.rb +12 -3
  19. data/lib/cancan/model_adapters/abstract_adapter.rb +10 -8
  20. data/lib/cancan/model_adapters/active_record_4_adapter.rb +39 -13
  21. data/lib/cancan/model_adapters/active_record_5_adapter.rb +68 -0
  22. data/lib/cancan/model_adapters/active_record_adapter.rb +77 -82
  23. data/lib/cancan/model_adapters/conditions_extractor.rb +75 -0
  24. data/lib/cancan/model_adapters/conditions_normalizer.rb +49 -0
  25. data/lib/cancan/model_adapters/default_adapter.rb +2 -0
  26. data/lib/cancan/model_additions.rb +2 -1
  27. data/lib/cancan/parameter_validators.rb +9 -0
  28. data/lib/cancan/relevant.rb +29 -0
  29. data/lib/cancan/rule.rb +76 -105
  30. data/lib/cancan/rules_compressor.rb +23 -0
  31. data/lib/cancan/unauthorized_message_resolver.rb +24 -0
  32. data/lib/cancan/version.rb +3 -1
  33. data/lib/cancancan.rb +2 -0
  34. data/lib/generators/cancan/ability/ability_generator.rb +4 -2
  35. data/lib/generators/cancan/ability/templates/ability.rb +2 -0
  36. metadata +66 -56
  37. data/.gitignore +0 -15
  38. data/.rspec +0 -1
  39. data/.travis.yml +0 -28
  40. data/Appraisals +0 -81
  41. data/CHANGELOG.rdoc +0 -518
  42. data/CONTRIBUTING.md +0 -23
  43. data/Gemfile +0 -3
  44. data/LICENSE +0 -22
  45. data/README.md +0 -214
  46. data/Rakefile +0 -9
  47. data/gemfiles/activerecord_3.2.gemfile +0 -16
  48. data/gemfiles/activerecord_4.0.gemfile +0 -17
  49. data/gemfiles/activerecord_4.1.gemfile +0 -17
  50. data/gemfiles/activerecord_4.2.gemfile +0 -18
  51. data/gemfiles/mongoid_2.x.gemfile +0 -16
  52. data/gemfiles/sequel_3.x.gemfile +0 -16
  53. data/lib/cancan/inherited_resource.rb +0 -20
  54. data/lib/cancan/model_adapters/active_record_3_adapter.rb +0 -16
  55. data/lib/cancan/model_adapters/mongoid_adapter.rb +0 -54
  56. data/lib/cancan/model_adapters/sequel_adapter.rb +0 -87
  57. data/spec/README.rdoc +0 -27
  58. data/spec/cancan/ability_spec.rb +0 -521
  59. data/spec/cancan/controller_additions_spec.rb +0 -141
  60. data/spec/cancan/controller_resource_spec.rb +0 -632
  61. data/spec/cancan/exceptions_spec.rb +0 -58
  62. data/spec/cancan/inherited_resource_spec.rb +0 -71
  63. data/spec/cancan/matchers_spec.rb +0 -29
  64. data/spec/cancan/model_adapters/active_record_4_adapter_spec.rb +0 -85
  65. data/spec/cancan/model_adapters/active_record_adapter_spec.rb +0 -384
  66. data/spec/cancan/model_adapters/default_adapter_spec.rb +0 -7
  67. data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +0 -227
  68. data/spec/cancan/model_adapters/sequel_adapter_spec.rb +0 -132
  69. data/spec/cancan/rule_spec.rb +0 -52
  70. data/spec/matchers.rb +0 -13
  71. data/spec/spec.opts +0 -2
  72. data/spec/spec_helper.rb +0 -27
  73. data/spec/support/ability.rb +0 -7
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CanCan
4
+ module Ability
5
+ module Actions
6
+ # Alias one or more actions into another one.
7
+ #
8
+ # alias_action :update, :destroy, :to => :modify
9
+ # can :modify, Comment
10
+ #
11
+ # Then :modify permission will apply to both :update and :destroy requests.
12
+ #
13
+ # can? :update, Comment # => true
14
+ # can? :destroy, Comment # => true
15
+ #
16
+ # This only works in one direction. Passing the aliased action into the "can?" call
17
+ # will not work because aliases are meant to generate more generic actions.
18
+ #
19
+ # alias_action :update, :destroy, :to => :modify
20
+ # can :update, Comment
21
+ # can? :modify, Comment # => false
22
+ #
23
+ # Unless that exact alias is used.
24
+ #
25
+ # can :modify, Comment
26
+ # can? :modify, Comment # => true
27
+ #
28
+ # The following aliases are added by default for conveniently mapping common controller actions.
29
+ #
30
+ # alias_action :index, :show, :to => :read
31
+ # alias_action :new, :to => :create
32
+ # alias_action :edit, :to => :update
33
+ #
34
+ # This way one can use params[:action] in the controller to determine the permission.
35
+ def alias_action(*args)
36
+ target = args.pop[:to]
37
+ validate_target(target)
38
+ aliased_actions[target] ||= []
39
+ aliased_actions[target] += args
40
+ end
41
+
42
+ # Returns a hash of aliased actions. The key is the target and the value is an array of actions aliasing the key.
43
+ def aliased_actions
44
+ @aliased_actions ||= default_alias_actions
45
+ end
46
+
47
+ # Removes previously aliased actions including the defaults.
48
+ def clear_aliased_actions
49
+ @aliased_actions = {}
50
+ end
51
+
52
+ private
53
+
54
+ def default_alias_actions
55
+ {
56
+ read: %i[index show],
57
+ create: [:new],
58
+ update: [:edit]
59
+ }
60
+ end
61
+
62
+ # Given an action, it will try to find all of the actions which are aliased to it.
63
+ # This does the opposite kind of lookup as expand_actions.
64
+ def aliases_for_action(action)
65
+ results = [action]
66
+ aliased_actions.each do |aliased_action, actions|
67
+ results += aliases_for_action(aliased_action) if actions.include? action
68
+ end
69
+ results
70
+ end
71
+
72
+ def expanded_actions
73
+ @expanded_actions ||= {}
74
+ end
75
+
76
+ # Accepts an array of actions and returns an array of actions which match.
77
+ # This should be called before "matches?" and other checking methods since they
78
+ # rely on the actions to be expanded.
79
+ def expand_actions(actions)
80
+ expanded_actions[actions] ||= begin
81
+ expanded = []
82
+ actions.each do |action|
83
+ expanded << action
84
+ if (aliases = aliased_actions[action])
85
+ expanded += expand_actions(aliases)
86
+ end
87
+ end
88
+ expanded
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CanCan
4
+ module Ability
5
+ module Rules
6
+ protected
7
+
8
+ # Must be protected as an ability can merge with other abilities.
9
+ # This means that an ability must expose their rules with another ability.
10
+ def rules
11
+ @rules ||= []
12
+ end
13
+
14
+ private
15
+
16
+ def add_rule(rule)
17
+ rules << rule
18
+ add_rule_to_index(rule, rules.size - 1)
19
+ end
20
+
21
+ def add_rule_to_index(rule, position)
22
+ @rules_index ||= Hash.new { |h, k| h[k] = [] }
23
+
24
+ subjects = rule.subjects.compact
25
+ subjects << :all if subjects.empty?
26
+
27
+ subjects.each do |subject|
28
+ @rules_index[subject] << position
29
+ end
30
+ end
31
+
32
+ # Returns an array of Rule instances which match the action and subject
33
+ # This does not take into consideration any hash conditions or block statements
34
+ def relevant_rules(action, subject)
35
+ return [] unless @rules
36
+
37
+ relevant = possible_relevant_rules(subject).select do |rule|
38
+ rule.expanded_actions = expand_actions(rule.actions)
39
+ rule.relevant? action, subject
40
+ end
41
+ relevant.reverse!.uniq!
42
+ optimize_order! relevant
43
+ relevant
44
+ end
45
+
46
+ def possible_relevant_rules(subject)
47
+ if subject.is_a?(Hash)
48
+ rules
49
+ else
50
+ positions = @rules_index.values_at(subject, *alternative_subjects(subject))
51
+ positions.flatten!.sort!
52
+ positions.map { |i| @rules[i] }
53
+ end
54
+ end
55
+
56
+ def relevant_rules_for_match(action, subject)
57
+ relevant_rules(action, subject).each do |rule|
58
+ next unless rule.only_raw_sql?
59
+
60
+ raise Error,
61
+ "The can? and cannot? call cannot be used with a raw sql 'can' definition."\
62
+ " The checking code cannot be determined for #{action.inspect} #{subject.inspect}"
63
+ end
64
+ end
65
+
66
+ def relevant_rules_for_query(action, subject)
67
+ rules = relevant_rules(action, subject).reject do |rule|
68
+ # reject 'cannot' rules with attributes when doing queries
69
+ rule.base_behavior == false && rule.attributes.present?
70
+ end
71
+ if rules.any?(&:only_block?)
72
+ raise Error, "The accessible_by call cannot be used with a block 'can' definition."\
73
+ "The SQL cannot be determined for #{action.inspect} #{subject.inspect}"
74
+ end
75
+ rules
76
+ end
77
+
78
+ # Optimizes the order of the rules, so that rules with the :all subject are evaluated first.
79
+ def optimize_order!(rules)
80
+ first_can_in_group = -1
81
+ rules.each_with_index do |rule, i|
82
+ (first_can_in_group = -1) && next unless rule.base_behavior
83
+ (first_can_in_group = i) && next if first_can_in_group == -1
84
+ next unless rule.subjects == [:all]
85
+
86
+ rules[i] = rules[first_can_in_group]
87
+ rules[first_can_in_group] = rule
88
+ first_can_in_group += 1
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CanCan
4
+ module Ability
5
+ module StrongParameterSupport
6
+ # Returns an array of attributes suitable for use with strong parameters
7
+ #
8
+ # Note: reversing the relevant rules is important. Normal order means that 'cannot'
9
+ # rules will come before 'can' rules. However, you can't remove attributes before
10
+ # they are added. The 'reverse' is so that attributes will be added before the
11
+ # 'cannot' rules remove them.
12
+ def permitted_attributes(action, subject)
13
+ relevant_rules(action, subject)
14
+ .reverse
15
+ .select { |rule| rule.matches_conditions? action, subject }
16
+ .each_with_object(Set.new) do |rule, set|
17
+ attributes = get_attributes(rule, subject)
18
+ # add attributes for 'can', remove them for 'cannot'
19
+ rule.base_behavior ? set.merge(attributes) : set.subtract(attributes)
20
+ end.to_a
21
+ end
22
+
23
+ private
24
+
25
+ def subject_class?(subject)
26
+ klass = (subject.is_a?(Hash) ? subject.values.first : subject).class
27
+ [Class, Module].include? klass
28
+ end
29
+
30
+ def get_attributes(rule, subject)
31
+ klass = subject_class?(subject) ? subject : subject.class
32
+ # empty attributes is an 'all'
33
+ if rule.attributes.empty? && klass < ActiveRecord::Base
34
+ klass.column_names.map(&:to_sym) - Array(klass.primary_key)
35
+ else
36
+ rule.attributes
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CanCan
4
+ module ConditionsMatcher
5
+ # Matches the block or conditions hash
6
+ def matches_conditions?(action, subject, attribute = nil, *extra_args)
7
+ return call_block_with_all(action, subject, extra_args) if @match_all
8
+ return matches_block_conditions(subject, attribute, *extra_args) if @block
9
+ return matches_non_block_conditions(subject) unless conditions_empty?
10
+
11
+ true
12
+ end
13
+
14
+ private
15
+
16
+ def subject_class?(subject)
17
+ klass = (subject.is_a?(Hash) ? subject.values.first : subject).class
18
+ [Class, Module].include? klass
19
+ end
20
+
21
+ def matches_block_conditions(subject, *extra_args)
22
+ return @base_behavior if subject_class?(subject)
23
+
24
+ @block.call(subject, *extra_args.compact)
25
+ end
26
+
27
+ def matches_non_block_conditions(subject)
28
+ return nested_subject_matches_conditions?(subject) if subject.class == Hash
29
+ return matches_conditions_hash?(subject) unless subject_class?(subject)
30
+
31
+ # Don't stop at "cannot" definitions when there are conditions.
32
+ @base_behavior
33
+ end
34
+
35
+ def nested_subject_matches_conditions?(subject_hash)
36
+ parent, _child = subject_hash.first
37
+ matches_conditions_hash?(parent, @conditions[parent.class.name.downcase.to_sym] || {})
38
+ end
39
+
40
+ # Checks if the given subject matches the given conditions hash.
41
+ # This behavior can be overriden by a model adapter by defining two class methods:
42
+ # override_matching_for_conditions?(subject, conditions) and
43
+ # matches_conditions_hash?(subject, conditions)
44
+ def matches_conditions_hash?(subject, conditions = @conditions)
45
+ return true if conditions.empty?
46
+
47
+ adapter = model_adapter(subject)
48
+
49
+ if adapter.override_conditions_hash_matching?(subject, conditions)
50
+ return adapter.matches_conditions_hash?(subject, conditions)
51
+ end
52
+
53
+ matches_all_conditions?(adapter, conditions, subject)
54
+ end
55
+
56
+ def matches_all_conditions?(adapter, conditions, subject)
57
+ conditions.all? do |name, value|
58
+ if adapter.override_condition_matching?(subject, name, value)
59
+ adapter.matches_condition?(subject, name, value)
60
+ else
61
+ condition_match?(subject.send(name), value)
62
+ end
63
+ end
64
+ end
65
+
66
+ def condition_match?(attribute, value)
67
+ case value
68
+ when Hash
69
+ hash_condition_match?(attribute, value)
70
+ when Range
71
+ value.cover?(attribute)
72
+ when Enumerable
73
+ value.include?(attribute)
74
+ else
75
+ attribute == value
76
+ end
77
+ end
78
+
79
+ def hash_condition_match?(attribute, value)
80
+ if attribute.is_a?(Array) || (defined?(ActiveRecord) && attribute.is_a?(ActiveRecord::Relation))
81
+ attribute.any? { |element| matches_conditions_hash?(element, value) }
82
+ else
83
+ attribute && matches_conditions_hash?(attribute, value)
84
+ end
85
+ end
86
+
87
+ def call_block_with_all(action, subject, *extra_args)
88
+ if subject.class == Class
89
+ @block.call(action, subject, nil, *extra_args)
90
+ else
91
+ @block.call(action, subject.class, subject, *extra_args)
92
+ end
93
+ end
94
+
95
+ def model_adapter(subject)
96
+ CanCan::ModelAdapters::AbstractAdapter.adapter_class(subject_class?(subject) ? subject : subject.class)
97
+ end
98
+
99
+ def conditions_empty?
100
+ # @conditions might be an ActiveRecord::Associations::CollectionProxy
101
+ # which it's `==` implementation will fetch all records for comparison
102
+
103
+ (@conditions.is_a?(Hash) && @conditions == {}) || @conditions.nil?
104
+ end
105
+ end
106
+ end
@@ -1,5 +1,6 @@
1
- module CanCan
1
+ # frozen_string_literal: true
2
2
 
3
+ module CanCan
3
4
  # This module is automatically included into all controllers.
4
5
  # It also makes the "can?" and "cannot?" methods available to all views.
5
6
  module ControllerAdditions
@@ -12,7 +13,7 @@ module CanCan
12
13
  # end
13
14
  #
14
15
  def load_and_authorize_resource(*args)
15
- cancan_resource_class.add_before_filter(self, :load_and_authorize_resource, *args)
16
+ cancan_resource_class.add_before_action(self, :load_and_authorize_resource, *args)
16
17
  end
17
18
 
18
19
  # Sets up a before filter which loads the model resource into an instance variable.
@@ -32,16 +33,16 @@ module CanCan
32
33
  # end
33
34
  #
34
35
  # 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
+ # the behavior through a before_action on certain actions.
36
37
  #
37
38
  # class BooksController < ApplicationController
38
- # before_filter :find_book_by_permalink, :only => :show
39
+ # before_action :find_book_by_permalink, :only => :show
39
40
  # load_resource
40
41
  #
41
42
  # private
42
43
  #
43
44
  # def find_book_by_permalink
44
- # @book = Book.find_by_permalink!(params[:id)
45
+ # @book = Book.find_by_permalink!(params[:id])
45
46
  # end
46
47
  # end
47
48
  #
@@ -72,8 +73,8 @@ module CanCan
72
73
  # Load this resource through another one. This should match the name of the parent instance variable or method.
73
74
  #
74
75
  # [:+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.
76
+ # The name of the association to fetch the child records through the parent resource.
77
+ # This is normally not needed because it defaults to the pluralized resource name.
77
78
  #
78
79
  # [:+shallow+]
79
80
  # Pass +true+ to allow this resource to be loaded directly when parent is +nil+. Defaults to +false+.
@@ -82,8 +83,8 @@ module CanCan
82
83
  # Pass +true+ if this is a singleton resource through a +has_one+ association.
83
84
  #
84
85
  # [:+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.
86
+ # True or false depending on if the resource is considered a parent resource.
87
+ # This defaults to +true+ if a resource name is given which does not match the controller.
87
88
  #
88
89
  # [:+class+]
89
90
  # The class to use for the model (string or constant).
@@ -115,10 +116,10 @@ module CanCan
115
116
  # load_resource :new => :build
116
117
  #
117
118
  # [:+prepend+]
118
- # Passing +true+ will use prepend_before_filter instead of a normal before_filter.
119
+ # Passing +true+ will use prepend_before_action instead of a normal before_action.
119
120
  #
120
121
  def load_resource(*args)
121
- cancan_resource_class.add_before_filter(self, :load_resource, *args)
122
+ cancan_resource_class.add_before_action(self, :load_resource, *args)
122
123
  end
123
124
 
124
125
  # Sets up a before filter which authorizes the resource using the instance variable.
@@ -160,8 +161,8 @@ module CanCan
160
161
  # Pass +true+ if this is a singleton resource through a +has_one+ association.
161
162
  #
162
163
  # [:+parent+]
163
- # True or false depending on if the resource is considered a parent resource. This defaults to +true+ if a resource
164
- # name is given which does not match the controller.
164
+ # True or false depending on if the resource is considered a parent resource.
165
+ # This defaults to +true+ if a resource name is given which does not match the controller.
165
166
  #
166
167
  # [:+class+]
167
168
  # The class to use for the model (string or constant). This passed in when the instance variable is not set.
@@ -174,10 +175,10 @@ module CanCan
174
175
  # Authorize conditions on this parent resource when instance isn't available.
175
176
  #
176
177
  # [:+prepend+]
177
- # Passing +true+ will use prepend_before_filter instead of a normal before_filter.
178
+ # Passing +true+ will use prepend_before_action instead of a normal before_action.
178
179
  #
179
180
  def authorize_resource(*args)
180
- cancan_resource_class.add_before_filter(self, :authorize_resource, *args)
181
+ cancan_resource_class.add_before_action(self, :authorize_resource, *args)
181
182
  end
182
183
 
183
184
  # Skip both the loading and authorization behavior of CanCan for this given controller. This is primarily
@@ -226,8 +227,9 @@ module CanCan
226
227
  cancan_skipper[:authorize][name] = options
227
228
  end
228
229
 
229
- # Add this to a controller to ensure it performs authorization through +authorized+! or +authorize_resource+ call.
230
- # If neither of these authorization methods are called, a CanCan::AuthorizationNotPerformed exception will be raised.
230
+ # Add this to a controller to ensure it performs authorization through +authorize+! or +authorize_resource+ call.
231
+ # If neither of these authorization methods are called,
232
+ # a CanCan::AuthorizationNotPerformed exception will be raised.
231
233
  # This is normally added to the ApplicationController to ensure all controller actions do authorization.
232
234
  #
233
235
  # class ApplicationController < ActionController::Base
@@ -244,22 +246,29 @@ module CanCan
244
246
  # Does not apply to given actions.
245
247
  #
246
248
  # [:+if+]
247
- # Supply the name of a controller method to be called. The authorization check only takes place if this returns true.
249
+ # Supply the name of a controller method to be called.
250
+ # The authorization check only takes place if this returns true.
248
251
  #
249
252
  # check_authorization :if => :admin_controller?
250
253
  #
251
254
  # [:+unless+]
252
- # Supply the name of a controller method to be called. The authorization check only takes place if this returns false.
255
+ # Supply the name of a controller method to be called.
256
+ # The authorization check only takes place if this returns false.
253
257
  #
254
258
  # check_authorization :unless => :devise_controller?
255
259
  #
256
260
  def check_authorization(options = {})
257
- self.after_filter(options.slice(:only, :except)) do |controller|
261
+ block = proc do |controller|
258
262
  next if controller.instance_variable_defined?(:@_authorized)
259
263
  next if options[:if] && !controller.send(options[:if])
260
264
  next if options[:unless] && controller.send(options[:unless])
261
- raise AuthorizationNotPerformed, "This action failed the check_authorization because it does not authorize_resource. Add skip_authorization_check to bypass this check."
265
+
266
+ raise AuthorizationNotPerformed,
267
+ 'This action failed the check_authorization because it does not authorize_resource. '\
268
+ 'Add skip_authorization_check to bypass this check.'
262
269
  end
270
+
271
+ send(:after_action, options.slice(:only, :except), &block)
263
272
  end
264
273
 
265
274
  # Call this in the class of a controller to skip the check_authorization behavior on the actions.
@@ -268,33 +277,25 @@ module CanCan
268
277
  # skip_authorization_check :only => :index
269
278
  # end
270
279
  #
271
- # Any arguments are passed to the +before_filter+ it triggers.
280
+ # Any arguments are passed to the +before_action+ it triggers.
272
281
  def skip_authorization_check(*args)
273
- self.before_filter(*args) do |controller|
274
- controller.instance_variable_set(:@_authorized, true)
275
- end
276
- end
277
-
278
- def skip_authorization(*args)
279
- raise ImplementationRemoved, "The CanCan skip_authorization method has been renamed to skip_authorization_check. Please update your code."
282
+ block = proc { |controller| controller.instance_variable_set(:@_authorized, true) }
283
+ send(:before_action, *args, &block)
280
284
  end
281
285
 
282
286
  def cancan_resource_class
283
- if ancestors.map(&:to_s).include? "InheritedResources::Actions"
284
- InheritedResource
285
- else
286
- ControllerResource
287
- end
287
+ ControllerResource
288
288
  end
289
289
 
290
290
  def cancan_skipper
291
- @_cancan_skipper ||= {:authorize => {}, :load => {}}
291
+ self._cancan_skipper ||= { authorize: {}, load: {} }
292
292
  end
293
293
  end
294
294
 
295
295
  def self.included(base)
296
296
  base.extend ClassMethods
297
297
  base.helper_method :can?, :cannot?, :current_ability if base.respond_to? :helper_method
298
+ base.class_attribute :_cancan_skipper
298
299
  end
299
300
 
300
301
  # Raises a CanCan::AccessDenied exception if the current_ability cannot
@@ -338,10 +339,6 @@ module CanCan
338
339
  current_ability.authorize!(*args)
339
340
  end
340
341
 
341
- def unauthorized!(message = nil)
342
- raise ImplementationRemoved, "The unauthorized! method has been removed from CanCan, use authorize! instead."
343
- end
344
-
345
342
  # Creates and returns the current user's ability and caches it. If you
346
343
  # want to override how the Ability is defined then this is the place.
347
344
  # Just define the method in the controller to change behavior.
@@ -390,8 +387,8 @@ module CanCan
390
387
  end
391
388
  end
392
389
 
393
- if defined? ActionController::Base
394
- ActionController::Base.class_eval do
390
+ if defined? ActiveSupport
391
+ ActiveSupport.on_load(:action_controller) do
395
392
  include CanCan::ControllerAdditions
396
393
  end
397
394
  end