cancancan 1.13.1 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|