cancancan 2.1.0 → 2.1.1

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.
@@ -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