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.
- checksums.yaml +5 -5
- data/cancancan.gemspec +18 -18
- data/init.rb +2 -0
- data/lib/cancan.rb +9 -11
- data/lib/cancan/ability.rb +93 -194
- data/lib/cancan/ability/actions.rb +93 -0
- data/lib/cancan/ability/rules.rb +93 -0
- data/lib/cancan/ability/strong_parameter_support.rb +41 -0
- data/lib/cancan/conditions_matcher.rb +106 -0
- data/lib/cancan/controller_additions.rb +38 -41
- data/lib/cancan/controller_resource.rb +52 -211
- data/lib/cancan/controller_resource_builder.rb +26 -0
- data/lib/cancan/controller_resource_finder.rb +42 -0
- data/lib/cancan/controller_resource_loader.rb +120 -0
- data/lib/cancan/controller_resource_name_finder.rb +23 -0
- data/lib/cancan/controller_resource_sanitizer.rb +32 -0
- data/lib/cancan/exceptions.rb +17 -5
- data/lib/cancan/matchers.rb +12 -3
- data/lib/cancan/model_adapters/abstract_adapter.rb +10 -8
- data/lib/cancan/model_adapters/active_record_4_adapter.rb +39 -13
- data/lib/cancan/model_adapters/active_record_5_adapter.rb +68 -0
- data/lib/cancan/model_adapters/active_record_adapter.rb +77 -82
- data/lib/cancan/model_adapters/conditions_extractor.rb +75 -0
- data/lib/cancan/model_adapters/conditions_normalizer.rb +49 -0
- data/lib/cancan/model_adapters/default_adapter.rb +2 -0
- data/lib/cancan/model_additions.rb +2 -1
- data/lib/cancan/parameter_validators.rb +9 -0
- data/lib/cancan/relevant.rb +29 -0
- data/lib/cancan/rule.rb +76 -105
- data/lib/cancan/rules_compressor.rb +23 -0
- data/lib/cancan/unauthorized_message_resolver.rb +24 -0
- data/lib/cancan/version.rb +3 -1
- data/lib/cancancan.rb +2 -0
- data/lib/generators/cancan/ability/ability_generator.rb +4 -2
- data/lib/generators/cancan/ability/templates/ability.rb +2 -0
- metadata +66 -56
- data/.gitignore +0 -15
- data/.rspec +0 -1
- data/.travis.yml +0 -28
- data/Appraisals +0 -81
- data/CHANGELOG.rdoc +0 -518
- data/CONTRIBUTING.md +0 -23
- data/Gemfile +0 -3
- data/LICENSE +0 -22
- data/README.md +0 -214
- data/Rakefile +0 -9
- data/gemfiles/activerecord_3.2.gemfile +0 -16
- data/gemfiles/activerecord_4.0.gemfile +0 -17
- data/gemfiles/activerecord_4.1.gemfile +0 -17
- data/gemfiles/activerecord_4.2.gemfile +0 -18
- data/gemfiles/mongoid_2.x.gemfile +0 -16
- data/gemfiles/sequel_3.x.gemfile +0 -16
- data/lib/cancan/inherited_resource.rb +0 -20
- data/lib/cancan/model_adapters/active_record_3_adapter.rb +0 -16
- data/lib/cancan/model_adapters/mongoid_adapter.rb +0 -54
- data/lib/cancan/model_adapters/sequel_adapter.rb +0 -87
- data/spec/README.rdoc +0 -27
- data/spec/cancan/ability_spec.rb +0 -521
- data/spec/cancan/controller_additions_spec.rb +0 -141
- data/spec/cancan/controller_resource_spec.rb +0 -632
- data/spec/cancan/exceptions_spec.rb +0 -58
- data/spec/cancan/inherited_resource_spec.rb +0 -71
- data/spec/cancan/matchers_spec.rb +0 -29
- data/spec/cancan/model_adapters/active_record_4_adapter_spec.rb +0 -85
- data/spec/cancan/model_adapters/active_record_adapter_spec.rb +0 -384
- data/spec/cancan/model_adapters/default_adapter_spec.rb +0 -7
- data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +0 -227
- data/spec/cancan/model_adapters/sequel_adapter_spec.rb +0 -132
- data/spec/cancan/rule_spec.rb +0 -52
- data/spec/matchers.rb +0 -13
- data/spec/spec.opts +0 -2
- data/spec/spec_helper.rb +0 -27
- 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
|
-
|
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.
|
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
|
36
|
+
# the behavior through a before_action on certain actions.
|
36
37
|
#
|
37
38
|
# class BooksController < ApplicationController
|
38
|
-
#
|
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.
|
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.
|
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
|
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.
|
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.
|
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
|
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.
|
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 +
|
230
|
-
# If neither of these authorization methods are called,
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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 +
|
280
|
+
# Any arguments are passed to the +before_action+ it triggers.
|
272
281
|
def skip_authorization_check(*args)
|
273
|
-
|
274
|
-
|
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
|
-
|
284
|
-
InheritedResource
|
285
|
-
else
|
286
|
-
ControllerResource
|
287
|
-
end
|
287
|
+
ControllerResource
|
288
288
|
end
|
289
289
|
|
290
290
|
def cancan_skipper
|
291
|
-
|
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?
|
394
|
-
|
390
|
+
if defined? ActiveSupport
|
391
|
+
ActiveSupport.on_load(:action_controller) do
|
395
392
|
include CanCan::ControllerAdditions
|
396
393
|
end
|
397
394
|
end
|