cancancan 2.1.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ module CanCan
2
+ module ControllerResourceNameFinder
3
+ protected
4
+
5
+ def name_from_controller
6
+ @params[:controller].split('/').last.singularize
7
+ end
8
+
9
+ def namespaced_name
10
+ [namespace, name].join('/').singularize.camelize.safe_constantize || name
11
+ end
12
+
13
+ def name
14
+ @name || name_from_controller
15
+ end
16
+
17
+ def namespace
18
+ @params[:controller].split('/')[0..-2]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ module CanCan
2
+ module ControllerResourceSanitizer
3
+ protected
4
+
5
+ def sanitize_parameters
6
+ case params_method
7
+ when Symbol
8
+ @controller.send(params_method)
9
+ when String
10
+ @controller.instance_eval(params_method)
11
+ when Proc
12
+ params_method.call(@controller)
13
+ end
14
+ end
15
+
16
+ def params_methods
17
+ methods = ["#{@params[:action]}_params".to_sym, "#{name}_params".to_sym, :resource_params]
18
+ methods.unshift(@options[:param_method]) if @options[:param_method].present?
19
+ methods
20
+ end
21
+
22
+ def params_method
23
+ params_methods.each do |method|
24
+ return method if (method.is_a?(Symbol) && @controller.respond_to?(method, true)) ||
25
+ method.is_a?(String) || method.is_a?(Proc)
26
+ end
27
+ nil
28
+ end
29
+ end
30
+ end
@@ -1,6 +1,9 @@
1
+ require_relative 'can_can/model_adapters/active_record_adapter/joins.rb'
1
2
  module CanCan
2
3
  module ModelAdapters
3
4
  module ActiveRecordAdapter
5
+ include CanCan::ModelAdapters::ActiveRecordAdapter::Joins
6
+
4
7
  # Returns conditions intended to be used inside a database query. Normally you will not call this
5
8
  # method directly, but instead go through ModelAdditions#accessible_by.
6
9
  #
@@ -21,54 +24,51 @@ module CanCan
21
24
  # Return the conditions directly if there's just one definition
22
25
  tableized_conditions(@rules.first.conditions).dup
23
26
  else
24
- @rules.reverse.inject(false_sql) do |sql, rule|
25
- merge_conditions(sql, tableized_conditions(rule.conditions).dup, rule.base_behavior)
26
- end
27
+ extract_multiple_conditions
28
+ end
29
+ end
30
+
31
+ def extract_multiple_conditions
32
+ @rules.reverse.inject(false_sql) do |sql, rule|
33
+ merge_conditions(sql, tableized_conditions(rule.conditions).dup, rule.base_behavior)
27
34
  end
28
35
  end
29
36
 
30
37
  def tableized_conditions(conditions, model_class = @model_class)
31
38
  return conditions unless conditions.is_a? Hash
32
39
  conditions.each_with_object({}) do |(name, value), result_hash|
33
- if value.is_a? Hash
34
- value = value.dup
35
- association_class = model_class.reflect_on_association(name).klass.name.constantize
36
- nested_resulted = value.each_with_object({}) do |(k, v), nested|
37
- if v.is_a? Hash
38
- value.delete(k)
39
- nested[k] = v
40
- else
41
- result_hash[model_class.reflect_on_association(name).table_name.to_sym] = value
42
- end
43
- nested
44
- end
45
- result_hash.merge!(tableized_conditions(nested_resulted, association_class))
46
- else
47
- result_hash[name] = value
48
- end
49
- result_hash
40
+ calculate_result_hash(model_class, name, result_hash, value)
50
41
  end
51
42
  end
52
43
 
53
- # Returns the associations used in conditions for the :joins option of a search.
54
- # See ModelAdditions#accessible_by
55
- def joins
56
- joins_hash = {}
57
- @rules.each do |rule|
58
- merge_joins(joins_hash, rule.associations_hash)
44
+ def calculate_result_hash(model_class, name, result_hash, value)
45
+ if value.is_a? Hash
46
+ association_class = model_class.reflect_on_association(name).klass.name.constantize
47
+ nested_resulted = calculate_nested(model_class, name, result_hash, value.dup)
48
+ result_hash.merge!(tableized_conditions(nested_resulted, association_class))
49
+ else
50
+ result_hash[name] = value
51
+ end
52
+ result_hash
53
+ end
54
+
55
+ def calculate_nested(model_class, name, result_hash, value)
56
+ value.each_with_object({}) do |(k, v), nested|
57
+ if v.is_a? Hash
58
+ value.delete(k)
59
+ nested[k] = v
60
+ else
61
+ result_hash[model_class.reflect_on_association(name).table_name.to_sym] = value
62
+ end
63
+ nested
59
64
  end
60
- clean_joins(joins_hash) unless joins_hash.empty?
61
65
  end
62
66
 
63
67
  def database_records
64
68
  if override_scope
65
69
  @model_class.where(nil).merge(override_scope)
66
70
  elsif @model_class.respond_to?(:where) && @model_class.respond_to?(:joins)
67
- if mergeable_conditions?
68
- build_relation(conditions)
69
- else
70
- build_relation(*@rules.map(&:conditions))
71
- end
71
+ mergeable_conditions? ? build_relation(conditions) : build_relation(*@rules.map(&:conditions))
72
72
  else
73
73
  @model_class.all(conditions: conditions, joins: joins)
74
74
  end
@@ -82,30 +82,35 @@ module CanCan
82
82
 
83
83
  def override_scope
84
84
  conditions = @rules.map(&:conditions).compact
85
- return unless defined?(ActiveRecord::Relation) && conditions.any? { |c| c.is_a?(ActiveRecord::Relation) }
86
- if conditions.size == 1
87
- conditions.first
88
- else
89
- rule_found = @rules.detect { |rule| rule.conditions.is_a?(ActiveRecord::Relation) }
90
- raise Error,
91
- 'Unable to merge an Active Record scope with other conditions. '\
92
- "Instead use a hash or SQL for #{rule_found.actions.first} #{rule_found.subjects.first} ability."
93
- end
85
+ return unless conditions.any? { |c| c.is_a?(ActiveRecord::Relation) }
86
+ return conditions.first if conditions.size == 1
87
+ raise_override_scope_error
88
+ end
89
+
90
+ def raise_override_scope_error
91
+ rule_found = @rules.detect { |rule| rule.conditions.is_a?(ActiveRecord::Relation) }
92
+ raise Error,
93
+ 'Unable to merge an Active Record scope with other conditions. '\
94
+ "Instead use a hash or SQL for #{rule_found.actions.first} #{rule_found.subjects.first} ability."
94
95
  end
95
96
 
96
97
  def merge_conditions(sql, conditions_hash, behavior)
97
98
  if conditions_hash.blank?
98
99
  behavior ? true_sql : false_sql
99
100
  else
100
- conditions = sanitize_sql(conditions_hash)
101
- case sql
102
- when true_sql
103
- behavior ? true_sql : "not (#{conditions})"
104
- when false_sql
105
- behavior ? conditions : false_sql
106
- else
107
- behavior ? "(#{conditions}) OR (#{sql})" : "not (#{conditions}) AND (#{sql})"
108
- end
101
+ merge_non_empty_conditions(behavior, conditions_hash, sql)
102
+ end
103
+ end
104
+
105
+ def merge_non_empty_conditions(behavior, conditions_hash, sql)
106
+ conditions = sanitize_sql(conditions_hash)
107
+ case sql
108
+ when true_sql
109
+ behavior ? true_sql : "not (#{conditions})"
110
+ when false_sql
111
+ behavior ? conditions : false_sql
112
+ else
113
+ behavior ? "(#{conditions}) OR (#{sql})" : "not (#{conditions}) AND (#{sql})"
109
114
  end
110
115
  end
111
116
 
@@ -120,26 +125,6 @@ module CanCan
120
125
  def sanitize_sql(conditions)
121
126
  @model_class.send(:sanitize_sql, conditions)
122
127
  end
123
-
124
- # Takes two hashes and does a deep merge.
125
- def merge_joins(base, add)
126
- add.each do |name, nested|
127
- if base[name].is_a?(Hash)
128
- merge_joins(base[name], nested) unless nested.empty?
129
- else
130
- base[name] = nested
131
- end
132
- end
133
- end
134
-
135
- # Removes empty hashes and moves everything into arrays.
136
- def clean_joins(joins_hash)
137
- joins = []
138
- joins_hash.each do |name, nested|
139
- joins << (nested.empty? ? name : { name => clean_joins(nested) })
140
- end
141
- joins
142
- end
143
128
  end
144
129
  end
145
130
  end
@@ -0,0 +1,39 @@
1
+ module CanCan
2
+ module ModelAdapters
3
+ module ActiveRecordAdapter
4
+ module Joins
5
+ # Returns the associations used in conditions for the :joins option of a search.
6
+ # See ModelAdditions#accessible_by
7
+ def joins
8
+ joins_hash = {}
9
+ @rules.each do |rule|
10
+ merge_joins(joins_hash, rule.associations_hash)
11
+ end
12
+ clean_joins(joins_hash) unless joins_hash.empty?
13
+ end
14
+
15
+ private
16
+
17
+ # Removes empty hashes and moves everything into arrays.
18
+ def clean_joins(joins_hash)
19
+ joins = []
20
+ joins_hash.each do |name, nested|
21
+ joins << (nested.empty? ? name : { name => clean_joins(nested) })
22
+ end
23
+ joins
24
+ end
25
+
26
+ # Takes two hashes and does a deep merge.
27
+ def merge_joins(base, add)
28
+ add.each do |name, nested|
29
+ if base[name].is_a?(Hash)
30
+ merge_joins(base[name], nested) unless nested.empty?
31
+ else
32
+ base[name] = nested
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,8 +1,10 @@
1
+ require_relative 'conditions_matcher.rb'
1
2
  module CanCan
2
3
  # This class is used internally and should only be called through Ability.
3
4
  # it holds the information about a "can" call made on Ability and provides
4
5
  # helpful methods to determine permission checking and conditions hash generation.
5
6
  class Rule # :nodoc:
7
+ include ConditionsMatcher
6
8
  attr_reader :base_behavior, :subjects, :actions, :conditions
7
9
  attr_writer :expanded_actions
8
10
 
@@ -28,22 +30,6 @@ module CanCan
28
30
  @match_all || (matches_action?(action) && matches_subject?(subject))
29
31
  end
30
32
 
31
- # Matches the block or conditions hash
32
- def matches_conditions?(action, subject, extra_args)
33
- if @match_all
34
- call_block_with_all(action, subject, extra_args)
35
- elsif @block && !subject_class?(subject)
36
- @block.call(subject, *extra_args)
37
- elsif @conditions.is_a?(Hash) && subject.class == Hash
38
- nested_subject_matches_conditions?(subject)
39
- elsif @conditions.is_a?(Hash) && !subject_class?(subject)
40
- matches_conditions_hash?(subject)
41
- else
42
- # Don't stop at "cannot" definitions when there are conditions.
43
- conditions_empty? ? true : @base_behavior
44
- end
45
- end
46
-
47
33
  def only_block?
48
34
  conditions_empty? && @block
49
35
  end
@@ -52,10 +38,6 @@ module CanCan
52
38
  @block.nil? && !conditions_empty? && !@conditions.is_a?(Hash)
53
39
  end
54
40
 
55
- def conditions_empty?
56
- @conditions == {} || @conditions.nil?
57
- end
58
-
59
41
  def unmergeable?
60
42
  @conditions.respond_to?(:keys) && @conditions.present? &&
61
43
  (!@conditions.keys.first.is_a? Symbol)
@@ -83,11 +65,6 @@ module CanCan
83
65
 
84
66
  private
85
67
 
86
- def subject_class?(subject)
87
- klass = (subject.is_a?(Hash) ? subject.values.first : subject).class
88
- klass == Class || klass == Module
89
- end
90
-
91
68
  def matches_action?(action)
92
69
  @expanded_actions.include?(:manage) || @expanded_actions.include?(action)
93
70
  end
@@ -99,64 +76,8 @@ module CanCan
99
76
  def matches_subject_class?(subject)
100
77
  @subjects.any? do |sub|
101
78
  sub.is_a?(Module) && (subject.is_a?(sub) ||
102
- subject.class.to_s == sub.to_s ||
103
- (subject.is_a?(Module) && subject.ancestors.include?(sub)))
104
- end
105
- end
106
-
107
- # Checks if the given subject matches the given conditions hash.
108
- # This behavior can be overriden by a model adapter by defining two class methods:
109
- # override_matching_for_conditions?(subject, conditions) and
110
- # matches_conditions_hash?(subject, conditions)
111
- def matches_conditions_hash?(subject, conditions = @conditions)
112
- return true if conditions.empty?
113
- adapter = model_adapter(subject)
114
-
115
- if adapter.override_conditions_hash_matching?(subject, conditions)
116
- return adapter.matches_conditions_hash?(subject, conditions)
117
- end
118
-
119
- conditions.all? do |name, value|
120
- if adapter.override_condition_matching?(subject, name, value)
121
- adapter.matches_condition?(subject, name, value)
122
- else
123
- condition_match?(subject.send(name), value)
124
- end
125
- end
126
- end
127
-
128
- def nested_subject_matches_conditions?(subject_hash)
129
- parent, _child = subject_hash.first
130
- matches_conditions_hash?(parent, @conditions[parent.class.name.downcase.to_sym] || {})
131
- end
132
-
133
- def call_block_with_all(action, subject, extra_args)
134
- if subject.class == Class
135
- @block.call(action, subject, nil, *extra_args)
136
- else
137
- @block.call(action, subject.class, subject, *extra_args)
138
- end
139
- end
140
-
141
- def model_adapter(subject)
142
- CanCan::ModelAdapters::AbstractAdapter.adapter_class(subject_class?(subject) ? subject : subject.class)
143
- end
144
-
145
- def condition_match?(attribute, value)
146
- case value
147
- when Hash then hash_condition_match?(attribute, value)
148
- when String then attribute == value
149
- when Range then value.cover?(attribute)
150
- when Enumerable then value.include?(attribute)
151
- else attribute == value
152
- end
153
- end
154
-
155
- def hash_condition_match?(attribute, value)
156
- if attribute.is_a?(Array) || (defined?(ActiveRecord) && attribute.is_a?(ActiveRecord::Relation))
157
- attribute.any? { |element| matches_conditions_hash?(element, value) }
158
- else
159
- attribute && matches_conditions_hash?(attribute, value)
79
+ subject.class.to_s == sub.to_s ||
80
+ (subject.is_a?(Module) && subject.ancestors.include?(sub)))
160
81
  end
161
82
  end
162
83
  end
@@ -1,3 +1,3 @@
1
1
  module CanCan
2
- VERSION = '2.1.0'.freeze
2
+ VERSION = '2.1.1'.freeze
3
3
  end
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: 2.1.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Rodi (Renuo AG)
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2017-11-10 00:00:00.000000000 Z
14
+ date: 2017-11-13 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -112,13 +112,22 @@ files:
112
112
  - init.rb
113
113
  - lib/cancan.rb
114
114
  - lib/cancan/ability.rb
115
+ - lib/cancan/ability/actions.rb
116
+ - lib/cancan/ability/rules.rb
117
+ - lib/cancan/conditions_matcher.rb
115
118
  - lib/cancan/controller_additions.rb
116
119
  - lib/cancan/controller_resource.rb
120
+ - lib/cancan/controller_resource_builder.rb
121
+ - lib/cancan/controller_resource_finder.rb
122
+ - lib/cancan/controller_resource_loader.rb
123
+ - lib/cancan/controller_resource_name_finder.rb
124
+ - lib/cancan/controller_resource_sanitizer.rb
117
125
  - lib/cancan/exceptions.rb
118
126
  - lib/cancan/matchers.rb
119
127
  - lib/cancan/model_adapters/abstract_adapter.rb
120
128
  - lib/cancan/model_adapters/active_record_4_adapter.rb
121
129
  - lib/cancan/model_adapters/active_record_adapter.rb
130
+ - lib/cancan/model_adapters/can_can/model_adapters/active_record_adapter/joins.rb
122
131
  - lib/cancan/model_adapters/default_adapter.rb
123
132
  - lib/cancan/model_additions.rb
124
133
  - lib/cancan/rule.rb