cancancan 1.13.1 → 3.1.0

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 (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