cancancan 3.6.2 → 3.7.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 +4 -4
- data/cancancan.gemspec +3 -2
- data/lib/cancan/ability/actions.rb +6 -3
- data/lib/cancan/ability/rules.rb +28 -1
- data/lib/cancan/ability/strong_parameter_support.rb +29 -15
- data/lib/cancan/ability.rb +13 -10
- data/lib/cancan/class_matcher.rb +1 -1
- data/lib/cancan/conditions_matcher.rb +20 -11
- data/lib/cancan/config.rb +21 -7
- data/lib/cancan/controller_additions.rb +3 -2
- data/lib/cancan/controller_resource.rb +247 -17
- data/lib/cancan/model_adapters/abstract_adapter.rb +9 -0
- data/lib/cancan/model_adapters/active_record_5_adapter.rb +28 -11
- data/lib/cancan/model_adapters/active_record_adapter.rb +81 -23
- data/lib/cancan/model_adapters/conditions_extractor.rb +94 -38
- data/lib/cancan/model_adapters/conditions_normalizer.rb +9 -1
- data/lib/cancan/model_adapters/sti_normalizer.rb +6 -13
- data/lib/cancan/model_adapters/strategies/joined_alias_each_rule_as_exists_subquery.rb +2 -2
- data/lib/cancan/relevant.rb +4 -0
- data/lib/cancan/rule.rb +3 -2
- data/lib/cancan/rules_compressor.rb +3 -2
- data/lib/cancan/sti_detector.rb +1 -1
- data/lib/cancan/unauthorized_message_resolver.rb +1 -0
- data/lib/cancan/version.rb +1 -1
- metadata +4 -14
- data/lib/cancan/controller_resource_builder.rb +0 -26
- data/lib/cancan/controller_resource_finder.rb +0 -42
- data/lib/cancan/controller_resource_loader.rb +0 -120
- data/lib/cancan/controller_resource_name_finder.rb +0 -23
- data/lib/cancan/controller_resource_sanitizer.rb +0 -32
|
@@ -1,74 +1,130 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# this class is responsible of converting the hash of conditions
|
|
4
|
-
# in "where conditions" to generate the sql query
|
|
5
|
-
#
|
|
6
|
-
# it
|
|
4
|
+
# in "where conditions" to generate the sql query.
|
|
5
|
+
# Every association is given the table alias that ActiveRecord gives it when joining the associations,
|
|
6
|
+
# so it walks the joins in the same order and registers every joined table, through tables included.
|
|
7
7
|
module CanCan
|
|
8
8
|
module ModelAdapters
|
|
9
9
|
class ConditionsExtractor
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
# Pass the associations given to `joins` and then to `left_joins`, as they are joined by ActiveRecord.
|
|
11
|
+
def initialize(model_class, *joins)
|
|
12
12
|
@root_model_class = model_class
|
|
13
|
+
@aliases = Hash.new(0)
|
|
14
|
+
@aliases[model_class.table_name] = 1
|
|
15
|
+
@table_aliases = {}
|
|
16
|
+
@joined_tables = {}
|
|
17
|
+
@model_classes = {}
|
|
18
|
+
joins.each { |associations| register_joins(model_class, joins_tree(associations), []) }
|
|
13
19
|
end
|
|
14
20
|
|
|
15
|
-
def tableize_conditions(conditions, model_class = @root_model_class,
|
|
21
|
+
def tableize_conditions(conditions, model_class = @root_model_class, path = [])
|
|
16
22
|
return conditions unless conditions.is_a? Hash
|
|
17
23
|
|
|
18
24
|
conditions.each_with_object({}) do |(key, value), result_hash|
|
|
19
25
|
if value.is_a? Hash
|
|
20
|
-
|
|
26
|
+
tableize_association(model_class, path + [key.to_sym], value, result_hash)
|
|
21
27
|
else
|
|
22
28
|
result_hash[key] = value
|
|
23
29
|
end
|
|
24
|
-
result_hash
|
|
25
30
|
end
|
|
26
31
|
end
|
|
27
32
|
|
|
33
|
+
# The model class of a table alias returned by tableize_conditions.
|
|
34
|
+
def model_class_for(table_alias)
|
|
35
|
+
@model_classes[table_alias.to_s]
|
|
36
|
+
end
|
|
37
|
+
|
|
28
38
|
private
|
|
29
39
|
|
|
30
|
-
def
|
|
31
|
-
reflection = model_class.reflect_on_association(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
def tableize_association(model_class, path, conditions, result_hash)
|
|
41
|
+
reflection = model_class.reflect_on_association(path.last)
|
|
42
|
+
table_alias = @table_aliases[path] || register_association(model_class, reflection, path)
|
|
43
|
+
nested, values = conditions.partition { |_key, value| value.is_a? Hash }.map(&:to_h)
|
|
44
|
+
result_hash[table_alias.to_sym] = values unless values.empty?
|
|
45
|
+
result_hash.merge!(tableize_conditions(nested, reflection.klass, path))
|
|
35
46
|
end
|
|
36
47
|
|
|
37
|
-
def
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
table_alias = generate_table_alias(model_class, relation_name, path_to_key)
|
|
44
|
-
result_hash[table_alias] = value
|
|
45
|
-
end
|
|
46
|
-
nested
|
|
48
|
+
def joins_tree(joins)
|
|
49
|
+
case joins
|
|
50
|
+
when Hash then joins.to_h { |name, nested| [name.to_sym, joins_tree(nested)] }
|
|
51
|
+
when Array then joins.each_with_object({}) { |nested, tree| tree.deep_merge!(joins_tree(nested)) }
|
|
52
|
+
when nil then {}
|
|
53
|
+
else { joins.to_sym => {} }
|
|
47
54
|
end
|
|
48
55
|
end
|
|
49
56
|
|
|
50
|
-
|
|
51
|
-
|
|
57
|
+
# Mirrors ActiveRecord::Associations::JoinDependency#walk: the associations already joined come first.
|
|
58
|
+
def register_joins(model_class, tree, path)
|
|
59
|
+
joined, missing = tree.partition { |name, _nested| @table_aliases.key?(path + [name]) }
|
|
60
|
+
(joined + missing).each do |name, nested|
|
|
61
|
+
reflection = model_class.reflect_on_association(name)
|
|
62
|
+
next if reflection.nil? || reflection.polymorphic?
|
|
63
|
+
|
|
64
|
+
register_association(model_class, reflection, path + [name]) unless @table_aliases.key?(path + [name])
|
|
65
|
+
register_joins(reflection.klass, nested, path + [name])
|
|
66
|
+
end
|
|
67
|
+
end
|
|
52
68
|
|
|
53
|
-
|
|
54
|
-
|
|
69
|
+
def register_association(parent_class, reflection, path)
|
|
70
|
+
chain = reflection.chain
|
|
71
|
+
table_alias = nil
|
|
72
|
+
chain.each_index do |index|
|
|
73
|
+
table, reused = join_table(parent_class, chain, index)
|
|
74
|
+
table_alias ||= table
|
|
75
|
+
break if reused
|
|
76
|
+
end
|
|
77
|
+
@model_classes[table_alias] = reflection.klass
|
|
78
|
+
@table_aliases[path] = table_alias
|
|
79
|
+
end
|
|
55
80
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
81
|
+
# Mirrors ActiveRecord::Associations::JoinDependency#make_constraints
|
|
82
|
+
def join_table(parent_class, chain, index)
|
|
83
|
+
root = index.zero?
|
|
84
|
+
remaining_chain = chain[index..]
|
|
85
|
+
table, terminated = @joined_tables[remaining_chain]
|
|
86
|
+
return reuse_joined_table(remaining_chain, table, root) if reuse_joined_table?(table, root, terminated)
|
|
87
|
+
|
|
88
|
+
table = aliased_table_for(chain[index].klass.table_name) do
|
|
89
|
+
name = chain[index].alias_candidate(parent_class.table_name)
|
|
90
|
+
root ? name : "#{name}_join"
|
|
91
|
+
end
|
|
92
|
+
@joined_tables[remaining_chain] ||= [table, root]
|
|
93
|
+
[table, false]
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def reuse_joined_table(remaining_chain, table, root)
|
|
97
|
+
@joined_tables[remaining_chain] = [table, root] if root
|
|
98
|
+
[table, true]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# ActiveRecord reuses the through tables of the associations already joined since version 6.1
|
|
102
|
+
def reuse_joined_table?(table, root, terminated)
|
|
103
|
+
table && (!root || !terminated) && ActiveRecordAdapter.version_greater_or_equal?('6.1.0')
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Mirrors ActiveRecord::Associations::AliasTracker#aliased_table_for
|
|
107
|
+
def aliased_table_for(table_name)
|
|
108
|
+
if @aliases[table_name].zero?
|
|
109
|
+
@aliases[table_name] = 1
|
|
110
|
+
return table_name
|
|
60
111
|
end
|
|
61
|
-
|
|
112
|
+
|
|
113
|
+
aliased_name = yield[0...table_alias_length].tr('.', '_')
|
|
114
|
+
count = @aliases[aliased_name] += 1
|
|
115
|
+
count > 1 ? "#{aliased_name[0, table_alias_length - 2]}_#{count}" : aliased_name
|
|
62
116
|
end
|
|
63
117
|
|
|
64
|
-
def
|
|
65
|
-
@
|
|
118
|
+
def table_alias_length
|
|
119
|
+
@table_alias_length ||= connection.table_alias_length
|
|
66
120
|
end
|
|
67
121
|
|
|
68
|
-
def
|
|
69
|
-
@
|
|
70
|
-
|
|
71
|
-
|
|
122
|
+
def connection
|
|
123
|
+
if @root_model_class.respond_to?(:lease_connection)
|
|
124
|
+
@root_model_class.lease_connection
|
|
125
|
+
else
|
|
126
|
+
@root_model_class.connection
|
|
127
|
+
end
|
|
72
128
|
end
|
|
73
129
|
end
|
|
74
130
|
end
|
|
@@ -41,7 +41,15 @@ module CanCan
|
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def normalizable_association?(reflection)
|
|
44
|
-
reflection.options[:through].present? &&
|
|
44
|
+
reflection.options[:through].present? &&
|
|
45
|
+
!reflection.options[:source_type].present? &&
|
|
46
|
+
!joinable_with_scope?(reflection)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# A through association with its own scope is not exploded, because its parts do not keep
|
|
50
|
+
# that scope. Active Record joins it with the scope, unless the scope takes the record as argument.
|
|
51
|
+
def joinable_with_scope?(reflection)
|
|
52
|
+
reflection.scope.present? && reflection.scope.arity.zero?
|
|
45
53
|
end
|
|
46
54
|
end
|
|
47
55
|
end
|
|
@@ -7,25 +7,18 @@ module CanCan
|
|
|
7
7
|
class StiNormalizer
|
|
8
8
|
class << self
|
|
9
9
|
def normalize(rules)
|
|
10
|
-
rules_cache = []
|
|
11
10
|
return unless defined?(ActiveRecord::Base)
|
|
12
11
|
|
|
13
|
-
rules.
|
|
14
|
-
subjects = rule.subjects.select do |subject|
|
|
15
|
-
update_rule(subject, rule, rules_cache)
|
|
16
|
-
end
|
|
17
|
-
subjects.length == rule.subjects.length
|
|
18
|
-
end
|
|
19
|
-
rules_cache.each { |rule| rules.push(rule) }
|
|
12
|
+
rules.replace(rules.flat_map { |rule| normalized_rules(rule) })
|
|
20
13
|
end
|
|
21
14
|
|
|
22
15
|
private
|
|
23
16
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
# The rules for the subclasses take the place of the original rule, so their precedence is kept.
|
|
18
|
+
def normalized_rules(rule)
|
|
19
|
+
sti_subjects = rule.subjects.select { |subject| StiDetector.sti_class?(subject) }
|
|
20
|
+
subclass_rules = sti_subjects.map { |subject| build_rule_for_subclass(rule, subject) }
|
|
21
|
+
sti_subjects.length == rule.subjects.length ? subclass_rules : [rule, *subclass_rules]
|
|
29
22
|
end
|
|
30
23
|
|
|
31
24
|
# create a new rule for the subclasses that links on the inheritance_column
|
|
@@ -25,9 +25,9 @@ module CanCan
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def sub_query_for_rule(rule)
|
|
28
|
-
conditions_extractor = ConditionsExtractor.new(model_class)
|
|
29
|
-
rule_where_conditions = extract_multiple_conditions(conditions_extractor, [rule])
|
|
30
28
|
joins_hash, left_joins_hash = extract_joins_from_rule(rule)
|
|
29
|
+
conditions_extractor = ConditionsExtractor.new(model_class, joins_hash, left_joins_hash)
|
|
30
|
+
rule_where_conditions = extract_multiple_conditions(conditions_extractor, [rule])
|
|
31
31
|
sub_query_for_rules_and_join_hashes(rule_where_conditions, joins_hash, left_joins_hash)
|
|
32
32
|
end
|
|
33
33
|
|
data/lib/cancan/relevant.rb
CHANGED
|
@@ -8,6 +8,10 @@ module CanCan
|
|
|
8
8
|
@match_all || (matches_action?(action) && matches_subject?(subject))
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
def only_for_subclasses_of?(klass)
|
|
12
|
+
!@subjects.empty? && @subjects.all? { |subject| subject.is_a?(Class) && subject < klass }
|
|
13
|
+
end
|
|
14
|
+
|
|
11
15
|
private
|
|
12
16
|
|
|
13
17
|
def matches_action?(action)
|
data/lib/cancan/rule.rb
CHANGED
|
@@ -28,7 +28,7 @@ module CanCan
|
|
|
28
28
|
raise Error, "Subject is required for #{action}" if action && subject.nil?
|
|
29
29
|
|
|
30
30
|
@base_behavior = base_behavior
|
|
31
|
-
@actions = wrap(action)
|
|
31
|
+
@actions = wrap(action).map(&:to_sym)
|
|
32
32
|
@subjects = wrap(subject)
|
|
33
33
|
@attributes = wrap(attributes)
|
|
34
34
|
@conditions = extra_args || {}
|
|
@@ -58,7 +58,8 @@ module CanCan
|
|
|
58
58
|
|
|
59
59
|
def catch_all?
|
|
60
60
|
(with_scope? && @conditions.where_values_hash.empty?) ||
|
|
61
|
-
(
|
|
61
|
+
((@subjects.all? { |subject| !StiDetector.sti_class?(subject) || subject.base_class == subject }) &&
|
|
62
|
+
(!with_scope? && [nil, false, [], {}, '', ' '].include?(@conditions)))
|
|
62
63
|
end
|
|
63
64
|
|
|
64
65
|
def only_block?
|
|
@@ -31,9 +31,10 @@ module CanCan
|
|
|
31
31
|
def simplify(rules)
|
|
32
32
|
seen = Set.new
|
|
33
33
|
rules.reverse_each.filter_map do |rule|
|
|
34
|
-
|
|
34
|
+
subjects_and_conditions = [rule.subjects, rule.conditions]
|
|
35
|
+
next if seen.include?(subjects_and_conditions)
|
|
35
36
|
|
|
36
|
-
seen.add(
|
|
37
|
+
seen.add(subjects_and_conditions)
|
|
37
38
|
rule
|
|
38
39
|
end.reverse
|
|
39
40
|
end
|
data/lib/cancan/sti_detector.rb
CHANGED
|
@@ -4,7 +4,7 @@ class StiDetector
|
|
|
4
4
|
def self.sti_class?(subject)
|
|
5
5
|
return false unless defined?(ActiveRecord::Base)
|
|
6
6
|
return false unless subject.respond_to?(:descends_from_active_record?)
|
|
7
|
-
return false if subject
|
|
7
|
+
return false if subject.descends_from_active_record?
|
|
8
8
|
return false unless subject < ActiveRecord::Base
|
|
9
9
|
|
|
10
10
|
true
|
data/lib/cancan/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cancancan
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alessandro Rodi (Renuo AG)
|
|
@@ -50,22 +50,16 @@ dependencies:
|
|
|
50
50
|
name: rake
|
|
51
51
|
requirement: !ruby/object:Gem::Requirement
|
|
52
52
|
requirements:
|
|
53
|
-
- - "~>"
|
|
54
|
-
- !ruby/object:Gem::Version
|
|
55
|
-
version: '10.1'
|
|
56
53
|
- - ">="
|
|
57
54
|
- !ruby/object:Gem::Version
|
|
58
|
-
version:
|
|
55
|
+
version: '0'
|
|
59
56
|
type: :development
|
|
60
57
|
prerelease: false
|
|
61
58
|
version_requirements: !ruby/object:Gem::Requirement
|
|
62
59
|
requirements:
|
|
63
|
-
- - "~>"
|
|
64
|
-
- !ruby/object:Gem::Version
|
|
65
|
-
version: '10.1'
|
|
66
60
|
- - ">="
|
|
67
61
|
- !ruby/object:Gem::Version
|
|
68
|
-
version:
|
|
62
|
+
version: '0'
|
|
69
63
|
- !ruby/object:Gem::Dependency
|
|
70
64
|
name: rspec
|
|
71
65
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -119,11 +113,6 @@ files:
|
|
|
119
113
|
- lib/cancan/config.rb
|
|
120
114
|
- lib/cancan/controller_additions.rb
|
|
121
115
|
- lib/cancan/controller_resource.rb
|
|
122
|
-
- lib/cancan/controller_resource_builder.rb
|
|
123
|
-
- lib/cancan/controller_resource_finder.rb
|
|
124
|
-
- lib/cancan/controller_resource_loader.rb
|
|
125
|
-
- lib/cancan/controller_resource_name_finder.rb
|
|
126
|
-
- lib/cancan/controller_resource_sanitizer.rb
|
|
127
116
|
- lib/cancan/exceptions.rb
|
|
128
117
|
- lib/cancan/matchers.rb
|
|
129
118
|
- lib/cancan/model_adapters/abstract_adapter.rb
|
|
@@ -155,6 +144,7 @@ homepage: https://github.com/CanCanCommunity/cancancan
|
|
|
155
144
|
licenses:
|
|
156
145
|
- MIT
|
|
157
146
|
metadata:
|
|
147
|
+
changelog_uri: https://github.com/CanCanCommunity/cancancan/blob/develop/CHANGELOG.md
|
|
158
148
|
funding_uri: https://github.com/sponsors/coorasse
|
|
159
149
|
rdoc_options: []
|
|
160
150
|
require_paths:
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module CanCan
|
|
4
|
-
module ControllerResourceBuilder
|
|
5
|
-
protected
|
|
6
|
-
|
|
7
|
-
def build_resource
|
|
8
|
-
resource = resource_base.new(resource_params || {})
|
|
9
|
-
assign_attributes(resource)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def assign_attributes(resource)
|
|
13
|
-
resource.send("#{parent_name}=", parent_resource) if @options[:singleton] && parent_resource
|
|
14
|
-
initial_attributes.each do |attr_name, value|
|
|
15
|
-
resource.send("#{attr_name}=", value)
|
|
16
|
-
end
|
|
17
|
-
resource
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def initial_attributes
|
|
21
|
-
current_ability.attributes_for(@params[:action].to_sym, resource_class).delete_if do |key, _value|
|
|
22
|
-
resource_params && resource_params.include?(key)
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module CanCan
|
|
4
|
-
module ControllerResourceFinder
|
|
5
|
-
protected
|
|
6
|
-
|
|
7
|
-
def find_resource
|
|
8
|
-
if @options[:singleton] && parent_resource.respond_to?(name)
|
|
9
|
-
parent_resource.send(name)
|
|
10
|
-
elsif @options[:find_by]
|
|
11
|
-
find_resource_using_find_by
|
|
12
|
-
else
|
|
13
|
-
adapter.find(resource_base, id_param)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def find_resource_using_find_by
|
|
18
|
-
find_by_dynamic_finder || find_by_find_by_finder || resource_base.send(@options[:find_by], id_param)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def find_by_dynamic_finder
|
|
22
|
-
method_name = "find_by_#{@options[:find_by]}!"
|
|
23
|
-
resource_base.send(method_name, id_param) if resource_base.respond_to? method_name
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def find_by_find_by_finder
|
|
27
|
-
resource_base.find_by(@options[:find_by].to_sym => id_param) if resource_base.respond_to? :find_by
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def id_param
|
|
31
|
-
@params[id_param_key].to_s if @params[id_param_key].present?
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def id_param_key
|
|
35
|
-
if @options[:id_param]
|
|
36
|
-
@options[:id_param]
|
|
37
|
-
else
|
|
38
|
-
parent? ? :"#{name}_id" : :id
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'controller_resource_finder.rb'
|
|
4
|
-
require_relative 'controller_resource_name_finder.rb'
|
|
5
|
-
require_relative 'controller_resource_builder.rb'
|
|
6
|
-
require_relative 'controller_resource_sanitizer.rb'
|
|
7
|
-
module CanCan
|
|
8
|
-
module ControllerResourceLoader
|
|
9
|
-
include CanCan::ControllerResourceNameFinder
|
|
10
|
-
include CanCan::ControllerResourceFinder
|
|
11
|
-
include CanCan::ControllerResourceBuilder
|
|
12
|
-
include CanCan::ControllerResourceSanitizer
|
|
13
|
-
|
|
14
|
-
def load_resource
|
|
15
|
-
return if skip?(:load)
|
|
16
|
-
|
|
17
|
-
if load_instance?
|
|
18
|
-
self.resource_instance ||= load_resource_instance
|
|
19
|
-
elsif load_collection?
|
|
20
|
-
self.collection_instance ||= load_collection
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
protected
|
|
25
|
-
|
|
26
|
-
def new_actions
|
|
27
|
-
%i[new create] + Array(@options[:new])
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def resource_params_by_key(key)
|
|
31
|
-
return unless @options[key] && @params.key?(extract_key(@options[key]))
|
|
32
|
-
|
|
33
|
-
@params[extract_key(@options[key])]
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def resource_params_by_namespaced_name
|
|
37
|
-
resource_params_by_key(:instance_name) || resource_params_by_key(:class) || (
|
|
38
|
-
params = @params[extract_key(namespaced_name)]
|
|
39
|
-
params.respond_to?(:to_h) ? params : nil)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def resource_params
|
|
43
|
-
if parameters_require_sanitizing? && params_method.present?
|
|
44
|
-
sanitize_parameters
|
|
45
|
-
else
|
|
46
|
-
resource_params_by_namespaced_name
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def fetch_parent(name)
|
|
51
|
-
if @controller.instance_variable_defined? "@#{name}"
|
|
52
|
-
@controller.instance_variable_get("@#{name}")
|
|
53
|
-
elsif @controller.respond_to?(name, true)
|
|
54
|
-
@controller.send(name)
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# The object to load this resource through.
|
|
59
|
-
def parent_resource
|
|
60
|
-
parent_name && fetch_parent(parent_name)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def parent_name
|
|
64
|
-
@options[:through] && [@options[:through]].flatten.detect { |i| fetch_parent(i) }
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def resource_base_through_parent_resource
|
|
68
|
-
if @options[:singleton]
|
|
69
|
-
resource_class
|
|
70
|
-
else
|
|
71
|
-
parent_resource.send(@options[:through_association] || name.to_s.pluralize)
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def resource_base_through
|
|
76
|
-
if parent_resource
|
|
77
|
-
resource_base_through_parent_resource
|
|
78
|
-
elsif @options[:shallow]
|
|
79
|
-
resource_class
|
|
80
|
-
else
|
|
81
|
-
# maybe this should be a record not found error instead?
|
|
82
|
-
raise AccessDenied.new(nil, authorization_action, resource_class)
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# The object that methods (such as "find", "new" or "build") are called on.
|
|
87
|
-
# If the :through option is passed it will go through an association on that instance.
|
|
88
|
-
# If the :shallow option is passed it will use the resource_class if there's no parent
|
|
89
|
-
# If the :singleton option is passed it won't use the association because it needs to be handled later.
|
|
90
|
-
def resource_base
|
|
91
|
-
@options[:through] ? resource_base_through : resource_class
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def parent_authorization_action
|
|
95
|
-
@options[:parent_action] || :show
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def authorization_action
|
|
99
|
-
parent? ? parent_authorization_action : @params[:action].to_sym
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def load_collection
|
|
103
|
-
resource_base.accessible_by(current_ability, authorization_action)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def load_resource_instance
|
|
107
|
-
if !parent? && new_actions.include?(@params[:action].to_sym)
|
|
108
|
-
build_resource
|
|
109
|
-
elsif id_param || @options[:singleton]
|
|
110
|
-
find_resource
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
private
|
|
115
|
-
|
|
116
|
-
def extract_key(value)
|
|
117
|
-
value.to_s.underscore.tr('/', '_')
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
end
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module CanCan
|
|
4
|
-
module ControllerResourceNameFinder
|
|
5
|
-
protected
|
|
6
|
-
|
|
7
|
-
def name_from_controller
|
|
8
|
-
@params[:controller].split('/').last.singularize
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def namespaced_name
|
|
12
|
-
[namespace, name].join('/').singularize.camelize.safe_constantize || name
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def name
|
|
16
|
-
@name || name_from_controller
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def namespace
|
|
20
|
-
@params[:controller].split('/')[0..-2]
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module CanCan
|
|
4
|
-
module ControllerResourceSanitizer
|
|
5
|
-
protected
|
|
6
|
-
|
|
7
|
-
def sanitize_parameters
|
|
8
|
-
case params_method
|
|
9
|
-
when Symbol
|
|
10
|
-
@controller.send(params_method)
|
|
11
|
-
when String
|
|
12
|
-
@controller.instance_eval(params_method)
|
|
13
|
-
when Proc
|
|
14
|
-
params_method.call(@controller)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def params_methods
|
|
19
|
-
methods = ["#{@params[:action]}_params".to_sym, "#{name}_params".to_sym, :resource_params]
|
|
20
|
-
methods.unshift(@options[:param_method]) if @options[:param_method].present?
|
|
21
|
-
methods
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def params_method
|
|
25
|
-
params_methods.each do |method|
|
|
26
|
-
return method if (method.is_a?(Symbol) && @controller.respond_to?(method, true)) ||
|
|
27
|
-
method.is_a?(String) || method.is_a?(Proc)
|
|
28
|
-
end
|
|
29
|
-
nil
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|