cancancan 3.3.0 → 3.4.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 +1 -1
- data/lib/cancan/class_matcher.rb +4 -0
- data/lib/cancan/conditions_matcher.rb +25 -6
- data/lib/cancan/config.rb +5 -1
- data/lib/cancan/controller_resource.rb +1 -1
- data/lib/cancan/matchers.rb +5 -3
- data/lib/cancan/model_adapters/abstract_adapter.rb +14 -0
- data/lib/cancan/model_adapters/active_record_5_adapter.rb +5 -9
- data/lib/cancan/model_adapters/active_record_adapter.rb +27 -0
- data/lib/cancan/model_adapters/conditions_extractor.rb +4 -4
- data/lib/cancan/model_adapters/conditions_normalizer.rb +1 -1
- data/lib/cancan/model_adapters/sti_normalizer.rb +4 -4
- data/lib/cancan/model_adapters/strategies/base.rb +40 -0
- data/lib/cancan/model_adapters/strategies/joined_alias_each_rule_as_exists_subquery.rb +93 -0
- data/lib/cancan/model_adapters/strategies/joined_alias_exists_subquery.rb +31 -0
- data/lib/cancan/model_adapters/strategies/left_join.rb +11 -0
- data/lib/cancan/model_adapters/strategies/subquery.rb +18 -0
- data/lib/cancan/rule.rb +1 -1
- data/lib/cancan/sti_detector.rb +12 -0
- data/lib/cancan/version.rb +1 -1
- data/lib/cancan.rb +5 -0
- data/lib/generators/cancan/ability/templates/ability.rb +7 -9
- metadata +23 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fc128fc4996aed8edaee7dcce7178ec47d06c63591bf03c7cb98dd3deec5c213
|
4
|
+
data.tar.gz: 4e3ee983874f8fbeb3f566c6e12aaba275990581e77938b73d0349ec1e867f6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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', '~>
|
28
|
+
s.add_development_dependency 'rubocop', '~> 1.26'
|
29
29
|
end
|
data/lib/cancan/class_matcher.rb
CHANGED
@@ -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,
|
37
|
-
|
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
|
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,
|
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
|
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
|
-
|
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
|
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
|
data/lib/cancan/matchers.rb
CHANGED
@@ -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
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
26
|
-
|
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
|
-
|
33
|
-
|
34
|
-
|
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
|
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
|
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
|
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
|
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
|
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
|
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.
|
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,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
@@ -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
|
data/lib/cancan/version.rb
CHANGED
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
|
7
|
+
# Define abilities for the user here. For example:
|
8
8
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
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, :
|
27
|
+
# can :update, Article, published: true
|
30
28
|
#
|
31
29
|
# See the wiki for details:
|
32
|
-
# https://github.com/CanCanCommunity/cancancan/
|
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.
|
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:
|
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:
|
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:
|
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.
|
175
|
+
rubygems_version: 3.3.3
|
170
176
|
signing_key:
|
171
177
|
specification_version: 4
|
172
178
|
summary: Simple authorization solution for Rails.
|