cancancan 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cd789707449c90277a31d5808e55c36140b88b3aa3c2b9035640d777220b2d27
4
- data.tar.gz: 64fbbaa5657ae8b334e7096f33eb12b975a224ea7c516c0091d3d7ac94c0acbd
3
+ metadata.gz: f63f1d6ab266068caab6e7baf2b628ae72a7e03a134116eda91473861b9df359
4
+ data.tar.gz: fbf6337f058ece9a2f01c990a55398489e0ea56888f0a5ce3b9f8d5e203c31ae
5
5
  SHA512:
6
- metadata.gz: 70ba8098042c7114a7cf419a892c12794089da88046873fb6abf1c45dac3854731adb860ff95d2556f7e9ffad4543b5f53dc05579defd5ff8273bcf51476e0ce
7
- data.tar.gz: 5d390ebd7fa75ffbff3783502d6bf329d5949787b70ccd26559d40be4471c61efb8f4ea4adc2d53b6bac81f9e32e619d3569c268ff8a6277f16cab72ea162bf5
6
+ metadata.gz: 24fcc98ce0592b263add65cf0bc75a7020d75777fea7c6902216f97bbc9c13a36b4d379194a142cd8a5e5a24dc1ae82c82a61d6d99143c30a9afe11133048528
7
+ data.tar.gz: 8873b440698a941314f67a748db86c2abe33e89417ae54d9f35769c29f904edc9eff5736d0bf55d53badc494b9bca9e0ac1761c1920067238628d23dc8e0c643
@@ -8,8 +8,10 @@ require 'cancan/exceptions'
8
8
 
9
9
  require 'cancan/model_adapters/abstract_adapter'
10
10
  require 'cancan/model_adapters/default_adapter'
11
+ require 'cancan/rules_compressor'
11
12
 
12
13
  if defined? ActiveRecord
14
+ require 'cancan/model_adapters/conditions_extractor'
13
15
  require 'cancan/model_adapters/active_record_adapter'
14
16
  require 'cancan/model_adapters/active_record_4_adapter'
15
17
  require 'cancan/model_adapters/active_record_5_adapter'
@@ -384,6 +384,8 @@ module CanCan
384
384
  end
385
385
  end
386
386
 
387
- ActiveSupport.on_load(:action_controller) do
388
- include CanCan::ControllerAdditions
387
+ if defined? ActiveSupport
388
+ ActiveSupport.on_load(:action_controller) do
389
+ include CanCan::ControllerAdditions
390
+ end
389
391
  end
@@ -11,6 +11,9 @@ module CanCan
11
11
  # Raised when using check_authorization without calling authorized!
12
12
  class AuthorizationNotPerformed < Error; end
13
13
 
14
+ # Raised when using a wrong association name
15
+ class WrongAssociationName < Error; end
16
+
14
17
  # This error is raised when a user isn't allowed to access a given controller action.
15
18
  # This usually happens within a call to ControllerAdditions#authorize! but can be
16
19
  # raised manually.
@@ -1,4 +1,6 @@
1
1
  require_relative 'can_can/model_adapters/active_record_adapter/joins.rb'
2
+ require_relative 'conditions_extractor.rb'
3
+ require 'cancan/rules_compressor'
2
4
  module CanCan
3
5
  module ModelAdapters
4
6
  module ActiveRecordAdapter
@@ -20,47 +22,19 @@ module CanCan
20
22
  # query(:manage, User).conditions # => "not (self_managed = 't') AND ((manager_id = 1) OR (id = 1))"
21
23
  #
22
24
  def conditions
23
- if @rules.size == 1 && @rules.first.base_behavior
25
+ compressed_rules = RulesCompressor.new(@rules.reverse).rules_collapsed.reverse
26
+ conditions_extractor = ConditionsExtractor.new(@model_class)
27
+ if compressed_rules.size == 1 && compressed_rules.first.base_behavior
24
28
  # Return the conditions directly if there's just one definition
25
- tableized_conditions(@rules.first.conditions).dup
29
+ conditions_extractor.tableize_conditions(compressed_rules.first.conditions).dup
26
30
  else
27
- extract_multiple_conditions
31
+ extract_multiple_conditions(conditions_extractor, compressed_rules)
28
32
  end
29
33
  end
30
34
 
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)
34
- end
35
- end
36
-
37
- def tableized_conditions(conditions, model_class = @model_class)
38
- return conditions unless conditions.is_a? Hash
39
- conditions.each_with_object({}) do |(name, value), result_hash|
40
- calculate_result_hash(model_class, name, result_hash, value)
41
- end
42
- end
43
-
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
35
+ def extract_multiple_conditions(conditions_extractor, rules)
36
+ rules.reverse.inject(false_sql) do |sql, rule|
37
+ merge_conditions(sql, conditions_extractor.tableize_conditions(rule.conditions).dup, rule.base_behavior)
64
38
  end
65
39
  end
66
40
 
@@ -6,7 +6,7 @@ module CanCan
6
6
  # See ModelAdditions#accessible_by
7
7
  def joins
8
8
  joins_hash = {}
9
- @rules.each do |rule|
9
+ @rules.reverse.each do |rule|
10
10
  merge_joins(joins_hash, rule.associations_hash)
11
11
  end
12
12
  clean_joins(joins_hash) unless joins_hash.empty?
@@ -0,0 +1,75 @@
1
+ # this class is responsible of converting the hash of conditions
2
+ # in "where conditions" to generate the sql query
3
+ # it consists of a names_cache that helps calculating the next name given to the association
4
+ # it tries to reflect the bahavior of ActiveRecord when generating aliases for tables.
5
+ module CanCan
6
+ module ModelAdapters
7
+ class ConditionsExtractor
8
+ def initialize(model_class)
9
+ @names_cache = { model_class.table_name => [] }.with_indifferent_access
10
+ @root_model_class = model_class
11
+ end
12
+
13
+ def tableize_conditions(conditions, model_class = @root_model_class, path_to_key = 0)
14
+ return conditions unless conditions.is_a? Hash
15
+ conditions.each_with_object({}) do |(key, value), result_hash|
16
+ if value.is_a? Hash
17
+ result_hash.merge!(calculate_result_hash(key, model_class, path_to_key, result_hash, value))
18
+ else
19
+ result_hash[key] = value
20
+ end
21
+ result_hash
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def calculate_result_hash(key, model_class, path_to_key, result_hash, value)
28
+ reflection = model_class.reflect_on_association(key)
29
+ unless reflection
30
+ raise WrongAssociationName, "association #{key} not defined in model #{model_class.name}"
31
+ end
32
+ nested_resulted = calculate_nested(model_class, result_hash, key, value.dup, path_to_key)
33
+ association_class = reflection.klass.name.constantize
34
+ tableize_conditions(nested_resulted, association_class, "#{path_to_key}_#{key}")
35
+ end
36
+
37
+ def calculate_nested(model_class, result_hash, relation_name, value, path_to_key)
38
+ value.each_with_object({}) do |(k, v), nested|
39
+ if v.is_a? Hash
40
+ value.delete(k)
41
+ nested[k] = v
42
+ else
43
+ table_alias = generate_table_alias(model_class, relation_name, path_to_key)
44
+ result_hash[table_alias] = value
45
+ end
46
+ nested
47
+ end
48
+ end
49
+
50
+ def generate_table_alias(model_class, relation_name, path_to_key)
51
+ table_alias = model_class.reflect_on_association(relation_name).table_name.to_sym
52
+
53
+ if alredy_used?(table_alias, relation_name, path_to_key)
54
+ table_alias = "#{relation_name.to_s.pluralize}_#{model_class.table_name}".to_sym
55
+
56
+ index = 1
57
+ while alredy_used?(table_alias, relation_name, path_to_key)
58
+ table_alias = "#{table_alias}_#{index += 1}".to_sym
59
+ end
60
+ end
61
+ add_to_cache(table_alias, relation_name, path_to_key)
62
+ end
63
+
64
+ def alredy_used?(table_alias, relation_name, path_to_key)
65
+ @names_cache[table_alias].try(:exclude?, "#{path_to_key}_#{relation_name}")
66
+ end
67
+
68
+ def add_to_cache(table_alias, relation_name, path_to_key)
69
+ @names_cache[table_alias] ||= []
70
+ @names_cache[table_alias] << "#{path_to_key}_#{relation_name}"
71
+ table_alias
72
+ end
73
+ end
74
+ end
75
+ end
@@ -24,6 +24,18 @@ module CanCan
24
24
  @block = block
25
25
  end
26
26
 
27
+ def can_rule?
28
+ base_behavior
29
+ end
30
+
31
+ def cannot_catch_all?
32
+ !can_rule? && catch_all?
33
+ end
34
+
35
+ def catch_all?
36
+ [nil, false, [], {}, '', ' '].include? @conditions
37
+ end
38
+
27
39
  # Matches both the subject and action, not necessarily the conditions
28
40
  def relevant?(action, subject)
29
41
  subject = subject.values.first if subject.class == Hash
@@ -0,0 +1,20 @@
1
+ require_relative 'conditions_matcher.rb'
2
+ module CanCan
3
+ class RulesCompressor
4
+ attr_reader :initial_rules, :rules_collapsed
5
+
6
+ def initialize(rules)
7
+ @initial_rules = rules
8
+ @rules_collapsed = compress(@initial_rules)
9
+ end
10
+
11
+ def compress(array)
12
+ idx = array.rindex(&:catch_all?)
13
+ return array unless idx
14
+ value = array[idx]
15
+ array[idx..-1]
16
+ .drop_while { |n| n.base_behavior == value.base_behavior }
17
+ .tap { |a| a.unshift(value) unless value.cannot_catch_all? }
18
+ end
19
+ end
20
+ end
@@ -1,3 +1,3 @@
1
1
  module CanCan
2
- VERSION = '2.2.0'.freeze
2
+ VERSION = '2.3.0'.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.2.0
4
+ version: 2.3.0
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: 2018-04-15 00:00:00.000000000 Z
14
+ date: 2018-09-16 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -129,9 +129,11 @@ files:
129
129
  - lib/cancan/model_adapters/active_record_5_adapter.rb
130
130
  - lib/cancan/model_adapters/active_record_adapter.rb
131
131
  - lib/cancan/model_adapters/can_can/model_adapters/active_record_adapter/joins.rb
132
+ - lib/cancan/model_adapters/conditions_extractor.rb
132
133
  - lib/cancan/model_adapters/default_adapter.rb
133
134
  - lib/cancan/model_additions.rb
134
135
  - lib/cancan/rule.rb
136
+ - lib/cancan/rules_compressor.rb
135
137
  - lib/cancan/version.rb
136
138
  - lib/cancancan.rb
137
139
  - lib/generators/cancan/ability/USAGE