cancancan 3.3.0 → 3.4.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: c4498ac94e1994faa4da80dc957d8c9564433d991048774f9ac2f051e60de580
4
- data.tar.gz: 74209123c4c49adcd1d2d81df1de61c5f8cc2f243fdcdb4d01d3e41731e4c266
3
+ metadata.gz: fc128fc4996aed8edaee7dcce7178ec47d06c63591bf03c7cb98dd3deec5c213
4
+ data.tar.gz: 4e3ee983874f8fbeb3f566c6e12aaba275990581e77938b73d0349ec1e867f6e
5
5
  SHA512:
6
- metadata.gz: eb7774650d12a7073d09bb713f7eedfd7d376689f6d6bb842620b325a814720172f4fec900705bcc0dd3bd90818a88d2ab7e3904ea3a5d004533e13b4bed1c4c
7
- data.tar.gz: a7a6fff07fbd7d52816dd960d00ae0baea7d50c5ed41d0abf32ac3a0c2b6bc3c557a4309944717b57aad785ad7dc394870c079b6a820b62798a373a9d9f8c2b0
6
+ metadata.gz: 4511dd58be6c2a2ce4bc28b382ece40ad367a1cf72f56d521fe2f38ca038eb6cb11a249a1d029346038cfec0e1828acadddf8ff9be14d6d59e5228b165811d49
7
+ data.tar.gz: 8d24834c3362f708a9979079eee089537975aefa25144a65eea006c137a75297f1341b6df24877c0c517b0e1c33e935a7c4d82bbedcca84e00100d0806812ff5
data/cancancan.gemspec CHANGED
@@ -25,5 +25,5 @@ Gem::Specification.new do |s|
25
25
  s.add_development_dependency 'bundler', '~> 2.0'
26
26
  s.add_development_dependency 'rake', '~> 10.1', '>= 10.1.1'
27
27
  s.add_development_dependency 'rspec', '~> 3.2', '>= 3.2.0'
28
- s.add_development_dependency 'rubocop', '~> 0.63.1'
28
+ s.add_development_dependency 'rubocop', '~> 1.26'
29
29
  end
@@ -1,3 +1,5 @@
1
+ require_relative 'sti_detector'
2
+
1
3
  # This class is responsible for matching classes and their subclasses as well as
2
4
  # upmatching classes to their ancestors.
3
5
  # This is used to generate sti connections
@@ -12,6 +14,8 @@ class SubjectClassMatcher
12
14
  def self.matching_class_check(subject, sub, has_subclasses)
13
15
  matches = matches_class_or_is_related(subject, sub)
14
16
  if has_subclasses
17
+ return matches unless StiDetector.sti_class?(sub)
18
+
15
19
  matches || subject.subclasses.include?(sub)
16
20
  else
17
21
  matches
@@ -33,16 +33,24 @@ module CanCan
33
33
  end
34
34
 
35
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] || {})
36
+ parent, child = subject_hash.first
37
+
38
+ matches_base_parent_conditions = matches_conditions_hash?(parent,
39
+ @conditions[parent.class.name.downcase.to_sym] || {})
40
+
41
+ adapter = model_adapter(parent)
42
+
43
+ matches_base_parent_conditions &&
44
+ (!adapter.override_nested_subject_conditions_matching?(parent, child, @conditions) ||
45
+ adapter.nested_subject_matches_conditions?(parent, child, @conditions))
38
46
  end
39
47
 
40
48
  # 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:
49
+ # This behavior can be overridden by a model adapter by defining two class methods:
42
50
  # override_matching_for_conditions?(subject, conditions) and
43
51
  # matches_conditions_hash?(subject, conditions)
44
52
  def matches_conditions_hash?(subject, conditions = @conditions)
45
- return true if conditions.empty?
53
+ return true if conditions.is_a?(Hash) && conditions.empty?
46
54
 
47
55
  adapter = model_adapter(subject)
48
56
 
@@ -50,10 +58,21 @@ module CanCan
50
58
  return adapter.matches_conditions_hash?(subject, conditions)
51
59
  end
52
60
 
53
- matches_all_conditions?(adapter, conditions, subject)
61
+ matches_all_conditions?(adapter, subject, conditions)
62
+ end
63
+
64
+ def matches_all_conditions?(adapter, subject, conditions)
65
+ if conditions.is_a?(Hash)
66
+ matches_hash_conditions(adapter, subject, conditions)
67
+ elsif conditions.respond_to?(:include?)
68
+ conditions.include?(subject)
69
+ else
70
+ puts "does #{subject} match #{conditions}?"
71
+ subject == conditions
72
+ end
54
73
  end
55
74
 
56
- def matches_all_conditions?(adapter, conditions, subject)
75
+ def matches_hash_conditions(adapter, subject, conditions)
57
76
  conditions.all? do |name, value|
58
77
  if adapter.override_condition_matching?(subject, name, value)
59
78
  adapter.matches_condition?(subject, name, value)
data/lib/cancan/config.rb CHANGED
@@ -3,7 +3,11 @@
3
3
  module CanCan
4
4
  def self.valid_accessible_by_strategies
5
5
  strategies = [:left_join]
6
- strategies << :subquery unless does_not_support_subquery_strategy?
6
+
7
+ unless does_not_support_subquery_strategy?
8
+ strategies.push(:joined_alias_exists_subquery, :joined_alias_each_rule_as_exists_subquery, :subquery)
9
+ end
10
+
7
11
  strategies
8
12
  end
9
13
 
@@ -54,7 +54,7 @@ module CanCan
54
54
 
55
55
  protected
56
56
 
57
- # Returns the class used for this resource. This can be overriden by the :class option.
57
+ # Returns the class used for this resource. This can be overridden by the :class option.
58
58
  # If +false+ is passed in it will use the resource name as a symbol in which case it should
59
59
  # only be used for authorization, not loading since there's no class to load through.
60
60
  def resource_class
@@ -13,9 +13,11 @@ Kernel.const_get(rspec_module)::Matchers.define :be_able_to do |*args|
13
13
  match do |ability|
14
14
  actions = args.first
15
15
  if actions.is_a? Array
16
- break false if actions.empty?
17
-
18
- actions.all? { |action| ability.can?(action, *args[1..-1]) }
16
+ if actions.empty?
17
+ false
18
+ else
19
+ actions.all? { |action| ability.can?(action, *args[1..-1]) }
20
+ end
19
21
  else
20
22
  ability.can?(*args)
21
23
  end
@@ -3,6 +3,8 @@
3
3
  module CanCan
4
4
  module ModelAdapters
5
5
  class AbstractAdapter
6
+ attr_reader :model_class
7
+
6
8
  def self.inherited(subclass)
7
9
  @subclasses ||= []
8
10
  @subclasses.insert(0, subclass)
@@ -33,6 +35,18 @@ module CanCan
33
35
  raise NotImplemented, 'This model adapter does not support matching on a conditions hash.'
34
36
  end
35
37
 
38
+ # Used above override_conditions_hash_matching to determine if this model adapter will override the
39
+ # matching behavior for nested subject.
40
+ # If this returns true then nested_subject_matches_conditions? will be called.
41
+ def self.override_nested_subject_conditions_matching?(_parent, _child, _all_conditions)
42
+ false
43
+ end
44
+
45
+ # Override if override_nested_subject_conditions_matching? returns true
46
+ def self.nested_subject_matches_conditions?(_parent, _child, _all_conditions)
47
+ raise NotImplemented, 'This model adapter does not support matching on a nested subject.'
48
+ end
49
+
36
50
  # Used to determine if this model adapter will override the matching behavior for a specific condition.
37
51
  # If this returns true then matches_condition? will be called. See Rule#matches_conditions_hash
38
52
  def self.override_condition_matching?(_subject, _name, _value)
@@ -22,16 +22,12 @@ module CanCan
22
22
  private
23
23
 
24
24
  def build_joins_relation(relation, *where_conditions)
25
- case CanCan.accessible_by_strategy
26
- when :subquery
27
- inner = @model_class.unscoped do
28
- @model_class.left_joins(joins).where(*where_conditions)
29
- end
30
- @model_class.where(@model_class.primary_key => inner)
25
+ strategy_class.new(adapter: self, relation: relation, where_conditions: where_conditions).execute!
26
+ end
31
27
 
32
- when :left_join
33
- relation.left_joins(joins).distinct
34
- end
28
+ def strategy_class
29
+ strategy_class_name = CanCan.accessible_by_strategy.to_s.camelize
30
+ CanCan::ModelAdapters::Strategies.const_get(strategy_class_name)
35
31
  end
36
32
 
37
33
  def sanitize_sql(conditions)
@@ -11,6 +11,8 @@ module CanCan
11
11
  Gem::Version.new(ActiveRecord.version).release < Gem::Version.new(version)
12
12
  end
13
13
 
14
+ attr_reader :compressed_rules
15
+
14
16
  def initialize(model_class, rules)
15
17
  super
16
18
  @compressed_rules = RulesCompressor.new(@rules.reverse).rules_collapsed.reverse
@@ -18,6 +20,31 @@ module CanCan
18
20
  ConditionsNormalizer.normalize(model_class, @compressed_rules)
19
21
  end
20
22
 
23
+ class << self
24
+ # When belongs_to parent_id is a condition for a model,
25
+ # we want to check the parent when testing ability for a hash {parent => model}
26
+ def override_nested_subject_conditions_matching?(parent, child, all_conditions)
27
+ parent_child_conditions(parent, child, all_conditions).present?
28
+ end
29
+
30
+ # parent_id condition can be an array of integer or one integer, we check the parent against this
31
+ def nested_subject_matches_conditions?(parent, child, all_conditions)
32
+ id_condition = parent_child_conditions(parent, child, all_conditions)
33
+ return id_condition.include?(parent.id) if id_condition.is_a? Array
34
+ return id_condition == parent.id if id_condition.is_a? Integer
35
+
36
+ false
37
+ end
38
+
39
+ def parent_child_conditions(parent, child, all_conditions)
40
+ child_class = child.is_a?(Class) ? child : child.class
41
+ foreign_key = child_class.reflect_on_all_associations(:belongs_to).find do |association|
42
+ association.klass == parent.class
43
+ end&.foreign_key&.to_sym
44
+ foreign_key.nil? ? nil : all_conditions[foreign_key]
45
+ end
46
+ end
47
+
21
48
  # Returns conditions intended to be used inside a database query. Normally you will not call this
22
49
  # method directly, but instead go through ModelAdditions#accessible_by.
23
50
  #
@@ -3,7 +3,7 @@
3
3
  # this class is responsible of converting the hash of conditions
4
4
  # in "where conditions" to generate the sql query
5
5
  # it consists of a names_cache that helps calculating the next name given to the association
6
- # it tries to reflect the bahavior of ActiveRecord when generating aliases for tables.
6
+ # it tries to reflect the behavior of ActiveRecord when generating aliases for tables.
7
7
  module CanCan
8
8
  module ModelAdapters
9
9
  class ConditionsExtractor
@@ -50,18 +50,18 @@ module CanCan
50
50
  def generate_table_alias(model_class, relation_name, path_to_key)
51
51
  table_alias = model_class.reflect_on_association(relation_name).table_name.to_sym
52
52
 
53
- if alredy_used?(table_alias, relation_name, path_to_key)
53
+ if already_used?(table_alias, relation_name, path_to_key)
54
54
  table_alias = "#{relation_name.to_s.pluralize}_#{model_class.table_name}".to_sym
55
55
 
56
56
  index = 1
57
- while alredy_used?(table_alias, relation_name, path_to_key)
57
+ while already_used?(table_alias, relation_name, path_to_key)
58
58
  table_alias = "#{table_alias}_#{index += 1}".to_sym
59
59
  end
60
60
  end
61
61
  add_to_cache(table_alias, relation_name, path_to_key)
62
62
  end
63
63
 
64
- def alredy_used?(table_alias, relation_name, path_to_key)
64
+ def already_used?(table_alias, relation_name, path_to_key)
65
65
  @names_cache[table_alias].try(:exclude?, "#{path_to_key}_#{relation_name}")
66
66
  end
67
67
 
@@ -1,6 +1,6 @@
1
1
  # this class is responsible of normalizing the hash of conditions
2
2
  # by exploding has_many through associations
3
- # when a condition is defined with an has_many thorugh association this is exploded in all its parts
3
+ # when a condition is defined with an has_many through association this is exploded in all its parts
4
4
  # TODO: it could identify STI and normalize it
5
5
  module CanCan
6
6
  module ModelAdapters
@@ -1,3 +1,5 @@
1
+ require_relative '../sti_detector'
2
+
1
3
  # this class is responsible for detecting sti classes and creating new rules for the
2
4
  # relevant subclasses, using the inheritance_column as a merger
3
5
  module CanCan
@@ -20,9 +22,7 @@ module CanCan
20
22
  private
21
23
 
22
24
  def update_rule(subject, rule, rules_cache)
23
- return false unless subject.respond_to?(:descends_from_active_record?)
24
- return false if subject == :all || subject.descends_from_active_record?
25
- return false unless subject < ActiveRecord::Base
25
+ return false unless StiDetector.sti_class?(subject)
26
26
 
27
27
  rules_cache.push(build_rule_for_subclass(rule, subject))
28
28
  true
@@ -31,7 +31,7 @@ module CanCan
31
31
  # create a new rule for the subclasses that links on the inheritance_column
32
32
  def build_rule_for_subclass(rule, subject)
33
33
  CanCan::Rule.new(rule.base_behavior, rule.actions, subject.superclass,
34
- rule.conditions.merge(subject.inheritance_column => subject.name), rule.block)
34
+ rule.conditions.merge(subject.inheritance_column => subject.sti_name), rule.block)
35
35
  end
36
36
  end
37
37
  end
@@ -0,0 +1,40 @@
1
+ module CanCan
2
+ module ModelAdapters
3
+ class Strategies
4
+ class Base
5
+ attr_reader :adapter, :relation, :where_conditions
6
+
7
+ delegate(
8
+ :compressed_rules,
9
+ :extract_multiple_conditions,
10
+ :joins,
11
+ :model_class,
12
+ :quoted_primary_key,
13
+ :quoted_aliased_table_name,
14
+ :quoted_table_name,
15
+ to: :adapter
16
+ )
17
+ delegate :connection, :quoted_primary_key, to: :model_class
18
+ delegate :quote_table_name, to: :connection
19
+
20
+ def initialize(adapter:, relation:, where_conditions:)
21
+ @adapter = adapter
22
+ @relation = relation
23
+ @where_conditions = where_conditions
24
+ end
25
+
26
+ def aliased_table_name
27
+ @aliased_table_name ||= "#{model_class.table_name}_alias"
28
+ end
29
+
30
+ def quoted_aliased_table_name
31
+ @quoted_aliased_table_name ||= quote_table_name(aliased_table_name)
32
+ end
33
+
34
+ def quoted_table_name
35
+ @quoted_table_name ||= quote_table_name(model_class.table_name)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: false
2
+
3
+ module CanCan
4
+ module ModelAdapters
5
+ class Strategies
6
+ class JoinedAliasEachRuleAsExistsSubquery < Base
7
+ def execute!
8
+ model_class
9
+ .joins(
10
+ "JOIN #{quoted_table_name} AS #{quoted_aliased_table_name} ON " \
11
+ "#{quoted_aliased_table_name}.#{quoted_primary_key} = #{quoted_table_name}.#{quoted_primary_key}"
12
+ )
13
+ .where(double_exists_sql)
14
+ end
15
+
16
+ def double_exists_sql
17
+ double_exists_sql = ''
18
+
19
+ compressed_rules.each_with_index do |rule, index|
20
+ double_exists_sql << ' OR ' if index.positive?
21
+ double_exists_sql << "EXISTS (#{sub_query_for_rule(rule).to_sql})"
22
+ end
23
+
24
+ double_exists_sql
25
+ end
26
+
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
+ joins_hash, left_joins_hash = extract_joins_from_rule(rule)
31
+ sub_query_for_rules_and_join_hashes(rule_where_conditions, joins_hash, left_joins_hash)
32
+ end
33
+
34
+ def sub_query_for_rules_and_join_hashes(rule_where_conditions, joins_hash, left_joins_hash)
35
+ model_class
36
+ .select('1')
37
+ .joins(joins_hash)
38
+ .left_joins(left_joins_hash)
39
+ .where(
40
+ "#{quoted_table_name}.#{quoted_primary_key} = " \
41
+ "#{quoted_aliased_table_name}.#{quoted_primary_key}"
42
+ )
43
+ .where(rule_where_conditions)
44
+ .limit(1)
45
+ end
46
+
47
+ def extract_joins_from_rule(rule)
48
+ joins = {}
49
+ left_joins = {}
50
+
51
+ extra_joins_recursive([], rule.conditions, joins, left_joins)
52
+ [joins, left_joins]
53
+ end
54
+
55
+ def extra_joins_recursive(current_path, conditions, joins, left_joins)
56
+ conditions.each do |key, value|
57
+ if value.is_a?(Hash)
58
+ current_path << key
59
+ extra_joins_recursive(current_path, value, joins, left_joins)
60
+ current_path.pop
61
+ else
62
+ extra_joins_recursive_merge_joins(current_path, value, joins, left_joins)
63
+ end
64
+ end
65
+ end
66
+
67
+ def extra_joins_recursive_merge_joins(current_path, value, joins, left_joins)
68
+ hash_joins = current_path_to_hash(current_path)
69
+
70
+ if value.nil?
71
+ left_joins.deep_merge!(hash_joins)
72
+ else
73
+ joins.deep_merge!(hash_joins)
74
+ end
75
+ end
76
+
77
+ # Converts an array like [:child, :grand_child] into a hash like {child: {grand_child: {}}
78
+ def current_path_to_hash(current_path)
79
+ hash_joins = {}
80
+ current_hash_joins = hash_joins
81
+
82
+ current_path.each do |path_part|
83
+ new_hash = {}
84
+ current_hash_joins[path_part] = new_hash
85
+ current_hash_joins = new_hash
86
+ end
87
+
88
+ hash_joins
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CanCan
4
+ module ModelAdapters
5
+ class Strategies
6
+ class JoinedAliasExistsSubquery < Base
7
+ def execute!
8
+ model_class
9
+ .joins(
10
+ "JOIN #{quoted_table_name} AS #{quoted_aliased_table_name} ON " \
11
+ "#{quoted_aliased_table_name}.#{quoted_primary_key} = #{quoted_table_name}.#{quoted_primary_key}"
12
+ )
13
+ .where("EXISTS (#{joined_alias_exists_subquery_inner_query.to_sql})")
14
+ end
15
+
16
+ def joined_alias_exists_subquery_inner_query
17
+ model_class
18
+ .unscoped
19
+ .select('1')
20
+ .left_joins(joins)
21
+ .where(*where_conditions)
22
+ .where(
23
+ "#{quoted_table_name}.#{quoted_primary_key} = " \
24
+ "#{quoted_aliased_table_name}.#{quoted_primary_key}"
25
+ )
26
+ .limit(1)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,11 @@
1
+ module CanCan
2
+ module ModelAdapters
3
+ class Strategies
4
+ class LeftJoin < Base
5
+ def execute!
6
+ relation.left_joins(joins).distinct
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ module CanCan
2
+ module ModelAdapters
3
+ class Strategies
4
+ class Subquery < Base
5
+ def execute!
6
+ build_joins_relation_subquery(where_conditions)
7
+ end
8
+
9
+ def build_joins_relation_subquery(where_conditions)
10
+ inner = model_class.unscoped do
11
+ model_class.left_joins(joins).where(*where_conditions)
12
+ end
13
+ model_class.where(model_class.primary_key => inner)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
data/lib/cancan/rule.rb CHANGED
@@ -70,7 +70,7 @@ module CanCan
70
70
  end
71
71
 
72
72
  def with_scope?
73
- @conditions.is_a?(ActiveRecord::Relation)
73
+ defined?(ActiveRecord) && @conditions.is_a?(ActiveRecord::Relation)
74
74
  end
75
75
 
76
76
  def associations_hash(conditions = @conditions)
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class StiDetector
4
+ def self.sti_class?(subject)
5
+ return false unless defined?(ActiveRecord::Base)
6
+ return false unless subject.respond_to?(:descends_from_active_record?)
7
+ return false if subject == :all || subject.descends_from_active_record?
8
+ return false unless subject < ActiveRecord::Base
9
+
10
+ true
11
+ end
12
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CanCan
4
- VERSION = '3.3.0'.freeze
4
+ VERSION = '3.4.0'.freeze
5
5
  end
data/lib/cancan.rb CHANGED
@@ -21,4 +21,9 @@ if defined? ActiveRecord
21
21
  require 'cancan/model_adapters/active_record_adapter'
22
22
  require 'cancan/model_adapters/active_record_4_adapter'
23
23
  require 'cancan/model_adapters/active_record_5_adapter'
24
+ require 'cancan/model_adapters/strategies/base'
25
+ require 'cancan/model_adapters/strategies/joined_alias_each_rule_as_exists_subquery'
26
+ require 'cancan/model_adapters/strategies/joined_alias_exists_subquery'
27
+ require 'cancan/model_adapters/strategies/left_join'
28
+ require 'cancan/model_adapters/strategies/subquery'
24
29
  end
@@ -4,14 +4,12 @@ class Ability
4
4
  include CanCan::Ability
5
5
 
6
6
  def initialize(user)
7
- # Define abilities for the passed in user here. For example:
7
+ # Define abilities for the user here. For example:
8
8
  #
9
- # user ||= User.new # guest user (not logged in)
10
- # if user.admin?
11
- # can :manage, :all
12
- # else
13
- # can :read, :all
14
- # end
9
+ # return unless user.present?
10
+ # can :read, :all
11
+ # return unless user.admin?
12
+ # can :manage, :all
15
13
  #
16
14
  # The first argument to `can` is the action you are giving the user
17
15
  # permission to do.
@@ -26,9 +24,9 @@ class Ability
26
24
  # objects.
27
25
  # For example, here the user can only update published articles.
28
26
  #
29
- # can :update, Article, :published => true
27
+ # can :update, Article, published: true
30
28
  #
31
29
  # See the wiki for details:
32
- # https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities
30
+ # https://github.com/CanCanCommunity/cancancan/blob/develop/docs/define_check_abilities.md
33
31
  end
34
32
  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: 3.3.0
4
+ version: 3.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Rodi (Renuo AG)
@@ -11,28 +11,28 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2021-06-21 00:00:00.000000000 Z
14
+ date: 2022-06-23 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: appraisal
18
18
  requirement: !ruby/object:Gem::Requirement
19
19
  requirements:
20
- - - ">="
21
- - !ruby/object:Gem::Version
22
- version: 2.0.0
23
20
  - - "~>"
24
21
  - !ruby/object:Gem::Version
25
22
  version: '2.0'
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 2.0.0
26
26
  type: :development
27
27
  prerelease: false
28
28
  version_requirements: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: 2.0.0
33
30
  - - "~>"
34
31
  - !ruby/object:Gem::Version
35
32
  version: '2.0'
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: 2.0.0
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: bundler
38
38
  requirement: !ruby/object:Gem::Requirement
@@ -71,36 +71,36 @@ dependencies:
71
71
  name: rspec
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
- - - ">="
75
- - !ruby/object:Gem::Version
76
- version: 3.2.0
77
74
  - - "~>"
78
75
  - !ruby/object:Gem::Version
79
76
  version: '3.2'
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: 3.2.0
80
80
  type: :development
81
81
  prerelease: false
82
82
  version_requirements: !ruby/object:Gem::Requirement
83
83
  requirements:
84
- - - ">="
85
- - !ruby/object:Gem::Version
86
- version: 3.2.0
87
84
  - - "~>"
88
85
  - !ruby/object:Gem::Version
89
86
  version: '3.2'
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 3.2.0
90
90
  - !ruby/object:Gem::Dependency
91
91
  name: rubocop
92
92
  requirement: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 0.63.1
96
+ version: '1.26'
97
97
  type: :development
98
98
  prerelease: false
99
99
  version_requirements: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 0.63.1
103
+ version: '1.26'
104
104
  description: Simple authorization solution for Rails. All permissions are stored in
105
105
  a single location.
106
106
  email: alessandro.rodi@renuo.ch
@@ -135,11 +135,17 @@ files:
135
135
  - lib/cancan/model_adapters/conditions_normalizer.rb
136
136
  - lib/cancan/model_adapters/default_adapter.rb
137
137
  - lib/cancan/model_adapters/sti_normalizer.rb
138
+ - lib/cancan/model_adapters/strategies/base.rb
139
+ - lib/cancan/model_adapters/strategies/joined_alias_each_rule_as_exists_subquery.rb
140
+ - lib/cancan/model_adapters/strategies/joined_alias_exists_subquery.rb
141
+ - lib/cancan/model_adapters/strategies/left_join.rb
142
+ - lib/cancan/model_adapters/strategies/subquery.rb
138
143
  - lib/cancan/model_additions.rb
139
144
  - lib/cancan/parameter_validators.rb
140
145
  - lib/cancan/relevant.rb
141
146
  - lib/cancan/rule.rb
142
147
  - lib/cancan/rules_compressor.rb
148
+ - lib/cancan/sti_detector.rb
143
149
  - lib/cancan/unauthorized_message_resolver.rb
144
150
  - lib/cancan/version.rb
145
151
  - lib/cancancan.rb
@@ -166,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
172
  - !ruby/object:Gem::Version
167
173
  version: '0'
168
174
  requirements: []
169
- rubygems_version: 3.0.6
175
+ rubygems_version: 3.3.3
170
176
  signing_key:
171
177
  specification_version: 4
172
178
  summary: Simple authorization solution for Rails.