cancancan 2.3.0 → 3.2.2
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 +6 -5
- data/init.rb +2 -0
- data/lib/cancan.rb +6 -0
- data/lib/cancan/ability.rb +54 -24
- data/lib/cancan/ability/actions.rb +2 -0
- data/lib/cancan/ability/rules.rb +14 -6
- data/lib/cancan/ability/strong_parameter_support.rb +41 -0
- data/lib/cancan/class_matcher.rb +26 -0
- data/lib/cancan/conditions_matcher.rb +25 -12
- data/lib/cancan/config.rb +54 -0
- data/lib/cancan/controller_additions.rb +4 -1
- data/lib/cancan/controller_resource.rb +6 -0
- data/lib/cancan/controller_resource_builder.rb +2 -0
- data/lib/cancan/controller_resource_finder.rb +2 -0
- data/lib/cancan/controller_resource_loader.rb +4 -0
- data/lib/cancan/controller_resource_name_finder.rb +2 -0
- data/lib/cancan/controller_resource_sanitizer.rb +2 -0
- data/lib/cancan/exceptions.rb +18 -2
- data/lib/cancan/matchers.rb +3 -0
- data/lib/cancan/model_adapters/abstract_adapter.rb +3 -1
- data/lib/cancan/model_adapters/active_record_4_adapter.rb +26 -25
- data/lib/cancan/model_adapters/active_record_5_adapter.rb +21 -26
- data/lib/cancan/model_adapters/active_record_adapter.rb +56 -14
- data/lib/cancan/model_adapters/conditions_extractor.rb +3 -3
- data/lib/cancan/model_adapters/conditions_normalizer.rb +49 -0
- data/lib/cancan/model_adapters/default_adapter.rb +2 -0
- data/lib/cancan/model_adapters/sti_normalizer.rb +39 -0
- data/lib/cancan/model_additions.rb +2 -0
- data/lib/cancan/parameter_validators.rb +9 -0
- data/lib/cancan/relevant.rb +29 -0
- data/lib/cancan/rule.rb +67 -23
- data/lib/cancan/rules_compressor.rb +3 -0
- data/lib/cancan/unauthorized_message_resolver.rb +24 -0
- data/lib/cancan/version.rb +3 -1
- data/lib/cancancan.rb +2 -0
- data/lib/generators/cancan/ability/ability_generator.rb +3 -1
- data/lib/generators/cancan/ability/templates/ability.rb +2 -0
- metadata +37 -30
- data/lib/cancan/model_adapters/can_can/model_adapters/active_record_adapter/joins.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64c041d800f42e86e488e7c0f46bad09c21ea0d075142d0693deed634feb1c37
|
4
|
+
data.tar.gz: 78fbf14fd5a661c92c76bd9204e7996c096cec7f82e1b2fd1f73d33acb23d99b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95f9e1b7c6bb47b5d8ed2172752f8c7e7d9c4fb4567e1b0f43a6bf97eae4ed7d4b2557e85a24ce92ddd526e870b538e59d05767a62705a072a2532208d81cd67
|
7
|
+
data.tar.gz: 0b24f5078921f372af6fa98d180cc1f9dd79c6d17cd502fac4bdd3e87ce196e2a714070133d63caaf916840ad5bc70c938a435949f1d50889b2dd5a89fde590c
|
data/cancancan.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
lib = File.expand_path('
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
5
|
require 'cancan/version'
|
6
6
|
|
@@ -10,6 +10,7 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.authors = ['Alessandro Rodi (Renuo AG)', 'Bryan Rite', 'Ryan Bates', 'Richard Wilson']
|
11
11
|
s.email = 'alessandro.rodi@renuo.ch'
|
12
12
|
s.homepage = 'https://github.com/CanCanCommunity/cancancan'
|
13
|
+
s.metadata = { 'funding_uri' => 'https://github.com/sponsors/coorasse' }
|
13
14
|
s.summary = 'Simple authorization solution for Rails.'
|
14
15
|
s.description = 'Simple authorization solution for Rails. All permissions are stored in a single location.'
|
15
16
|
s.platform = Gem::Platform::RUBY
|
@@ -20,9 +21,9 @@ Gem::Specification.new do |s|
|
|
20
21
|
|
21
22
|
s.required_ruby_version = '>= 2.2.0'
|
22
23
|
|
23
|
-
s.add_development_dependency '
|
24
|
-
s.add_development_dependency '
|
24
|
+
s.add_development_dependency 'appraisal', '~> 2.0', '>= 2.0.0'
|
25
|
+
s.add_development_dependency 'bundler', '~> 2.0'
|
25
26
|
s.add_development_dependency 'rake', '~> 10.1', '>= 10.1.1'
|
26
27
|
s.add_development_dependency 'rspec', '~> 3.2', '>= 3.2.0'
|
27
|
-
s.add_development_dependency '
|
28
|
+
s.add_development_dependency 'rubocop', '~> 0.63.1'
|
28
29
|
end
|
data/init.rb
CHANGED
data/lib/cancan.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cancan/version'
|
4
|
+
require 'cancan/config'
|
5
|
+
require 'cancan/parameter_validators'
|
2
6
|
require 'cancan/ability'
|
3
7
|
require 'cancan/rule'
|
4
8
|
require 'cancan/controller_resource'
|
@@ -12,6 +16,8 @@ require 'cancan/rules_compressor'
|
|
12
16
|
|
13
17
|
if defined? ActiveRecord
|
14
18
|
require 'cancan/model_adapters/conditions_extractor'
|
19
|
+
require 'cancan/model_adapters/conditions_normalizer'
|
20
|
+
require 'cancan/model_adapters/sti_normalizer'
|
15
21
|
require 'cancan/model_adapters/active_record_adapter'
|
16
22
|
require 'cancan/model_adapters/active_record_4_adapter'
|
17
23
|
require 'cancan/model_adapters/active_record_5_adapter'
|
data/lib/cancan/ability.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'ability/rules.rb'
|
2
4
|
require_relative 'ability/actions.rb'
|
5
|
+
require_relative 'unauthorized_message_resolver.rb'
|
6
|
+
require_relative 'ability/strong_parameter_support'
|
7
|
+
|
3
8
|
module CanCan
|
4
9
|
# This module is designed to be included into an Ability class. This will
|
5
10
|
# provide the "can" methods for defining and checking abilities.
|
@@ -19,6 +24,8 @@ module CanCan
|
|
19
24
|
module Ability
|
20
25
|
include CanCan::Ability::Rules
|
21
26
|
include CanCan::Ability::Actions
|
27
|
+
include CanCan::UnauthorizedMessageResolver
|
28
|
+
include StrongParameterSupport
|
22
29
|
|
23
30
|
# Check if the user has permission to perform a given action on an object.
|
24
31
|
#
|
@@ -64,10 +71,10 @@ module CanCan
|
|
64
71
|
# end
|
65
72
|
#
|
66
73
|
# Also see the RSpec Matchers to aid in testing.
|
67
|
-
def can?(action, subject, *extra_args)
|
74
|
+
def can?(action, subject, attribute = nil, *extra_args)
|
68
75
|
match = extract_subjects(subject).lazy.map do |a_subject|
|
69
76
|
relevant_rules_for_match(action, a_subject).detect do |rule|
|
70
|
-
rule.matches_conditions?(action, a_subject, extra_args)
|
77
|
+
rule.matches_conditions?(action, a_subject, attribute, *extra_args) && rule.matches_attributes?(attribute)
|
71
78
|
end
|
72
79
|
end.reject(&:nil?).first
|
73
80
|
match ? match.base_behavior : false
|
@@ -134,8 +141,8 @@ module CanCan
|
|
134
141
|
# # check the database and return true/false
|
135
142
|
# end
|
136
143
|
#
|
137
|
-
def can(action = nil, subject = nil,
|
138
|
-
add_rule(Rule.new(true, action, subject,
|
144
|
+
def can(action = nil, subject = nil, *attributes_and_conditions, &block)
|
145
|
+
add_rule(Rule.new(true, action, subject, *attributes_and_conditions, &block))
|
139
146
|
end
|
140
147
|
|
141
148
|
# Defines an ability which cannot be done. Accepts the same arguments as "can".
|
@@ -150,8 +157,8 @@ module CanCan
|
|
150
157
|
# product.invisible?
|
151
158
|
# end
|
152
159
|
#
|
153
|
-
def cannot(action = nil, subject = nil,
|
154
|
-
add_rule(Rule.new(false, action, subject,
|
160
|
+
def cannot(action = nil, subject = nil, *attributes_and_conditions, &block)
|
161
|
+
add_rule(Rule.new(false, action, subject, *attributes_and_conditions, &block))
|
155
162
|
end
|
156
163
|
|
157
164
|
# User shouldn't specify targets with names of real actions or it will cause Seg fault
|
@@ -167,10 +174,7 @@ module CanCan
|
|
167
174
|
|
168
175
|
# See ControllerAdditions#authorize! for documentation.
|
169
176
|
def authorize!(action, subject, *args)
|
170
|
-
message = nil
|
171
|
-
if args.last.is_a?(Hash) && args.last.key?(:message)
|
172
|
-
message = args.pop[:message]
|
173
|
-
end
|
177
|
+
message = args.last.is_a?(Hash) && args.last.key?(:message) ? args.pop[:message] : nil
|
174
178
|
if cannot?(action, subject, *args)
|
175
179
|
message ||= unauthorized_message(action, subject)
|
176
180
|
raise AccessDenied.new(message, action, subject, args)
|
@@ -178,14 +182,6 @@ module CanCan
|
|
178
182
|
subject
|
179
183
|
end
|
180
184
|
|
181
|
-
def unauthorized_message(action, subject)
|
182
|
-
keys = unauthorized_message_keys(action, subject)
|
183
|
-
variables = { action: action.to_s }
|
184
|
-
variables[:subject] = (subject.class == Class ? subject : subject.class).to_s.underscore.humanize.downcase
|
185
|
-
message = I18n.translate(keys.shift, variables.merge(scope: :unauthorized, default: keys + ['']))
|
186
|
-
message.blank? ? nil : message
|
187
|
-
end
|
188
|
-
|
189
185
|
def attributes_for(action, subject)
|
190
186
|
attributes = {}
|
191
187
|
relevant_rules(action, subject).map do |rule|
|
@@ -202,12 +198,13 @@ module CanCan
|
|
202
198
|
relevant_rules(action, subject).any?(&:only_raw_sql?)
|
203
199
|
end
|
204
200
|
|
205
|
-
# Copies all rules of the given +CanCan::Ability+ and adds them to +self+.
|
201
|
+
# Copies all rules and aliased actions of the given +CanCan::Ability+ and adds them to +self+.
|
206
202
|
# class ReadAbility
|
207
203
|
# include CanCan::Ability
|
208
204
|
#
|
209
205
|
# def initialize
|
210
206
|
# can :read, User
|
207
|
+
# alias_action :show, :index, to: :see
|
211
208
|
# end
|
212
209
|
# end
|
213
210
|
#
|
@@ -216,6 +213,7 @@ module CanCan
|
|
216
213
|
#
|
217
214
|
# def initialize
|
218
215
|
# can :edit, User
|
216
|
+
# alias_action :create, :update, to: :modify
|
219
217
|
# end
|
220
218
|
# end
|
221
219
|
#
|
@@ -223,11 +221,35 @@ module CanCan
|
|
223
221
|
# read_ability.can? :edit, User.new #=> false
|
224
222
|
# read_ability.merge(WritingAbility.new)
|
225
223
|
# read_ability.can? :edit, User.new #=> true
|
224
|
+
# read_ability.aliased_actions #=> [:see => [:show, :index], :modify => [:create, :update]]
|
225
|
+
#
|
226
|
+
# If there are collisions when merging the +aliased_actions+, the actions on +self+ will be
|
227
|
+
# overwritten.
|
226
228
|
#
|
229
|
+
# class ReadAbility
|
230
|
+
# include CanCan::Ability
|
231
|
+
#
|
232
|
+
# def initialize
|
233
|
+
# alias_action :show, :index, to: :see
|
234
|
+
# end
|
235
|
+
# end
|
236
|
+
#
|
237
|
+
# class ShowAbility
|
238
|
+
# include CanCan::Ability
|
239
|
+
#
|
240
|
+
# def initialize
|
241
|
+
# alias_action :show, to: :see
|
242
|
+
# end
|
243
|
+
# end
|
244
|
+
#
|
245
|
+
# read_ability = ReadAbility.new
|
246
|
+
# read_ability.merge(ShowAbility)
|
247
|
+
# read_ability.aliased_actions #=> [:see => [:show]]
|
227
248
|
def merge(ability)
|
228
249
|
ability.rules.each do |rule|
|
229
250
|
add_rule(rule.dup)
|
230
251
|
end
|
252
|
+
@aliased_actions = aliased_actions.merge(ability.aliased_actions)
|
231
253
|
self
|
232
254
|
end
|
233
255
|
|
@@ -239,10 +261,13 @@ module CanCan
|
|
239
261
|
#
|
240
262
|
# Where can_hash and cannot_hash are formatted thusly:
|
241
263
|
# {
|
242
|
-
# action:
|
264
|
+
# action: { subject: [attributes] }
|
243
265
|
# }
|
244
266
|
def permissions
|
245
|
-
permissions_list = {
|
267
|
+
permissions_list = {
|
268
|
+
can: Hash.new { |actions, k1| actions[k1] = Hash.new { |subjects, k2| subjects[k2] = [] } },
|
269
|
+
cannot: Hash.new { |actions, k1| actions[k1] = Hash.new { |subjects, k2| subjects[k2] = [] } }
|
270
|
+
}
|
246
271
|
rules.each { |rule| extract_rule_in_permissions(permissions_list, rule) }
|
247
272
|
permissions_list
|
248
273
|
end
|
@@ -250,8 +275,9 @@ module CanCan
|
|
250
275
|
def extract_rule_in_permissions(permissions_list, rule)
|
251
276
|
expand_actions(rule.actions).each do |action|
|
252
277
|
container = rule.base_behavior ? :can : :cannot
|
253
|
-
|
254
|
-
|
278
|
+
rule.subjects.each do |subject|
|
279
|
+
permissions_list[container][action][subject.to_s] += rule.attributes
|
280
|
+
end
|
255
281
|
end
|
256
282
|
end
|
257
283
|
|
@@ -276,7 +302,11 @@ module CanCan
|
|
276
302
|
|
277
303
|
def alternative_subjects(subject)
|
278
304
|
subject = subject.class unless subject.is_a?(Module)
|
279
|
-
|
305
|
+
if subject.respond_to?(:subclasses) && defined?(ActiveRecord::Base) && subject < ActiveRecord::Base
|
306
|
+
[:all, *(subject.ancestors + subject.subclasses), subject.class.to_s]
|
307
|
+
else
|
308
|
+
[:all, *subject.ancestors, subject.class.to_s]
|
309
|
+
end
|
280
310
|
end
|
281
311
|
end
|
282
312
|
end
|
data/lib/cancan/ability/rules.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CanCan
|
2
4
|
module Ability
|
3
5
|
module Rules
|
@@ -31,6 +33,7 @@ module CanCan
|
|
31
33
|
# This does not take into consideration any hash conditions or block statements
|
32
34
|
def relevant_rules(action, subject)
|
33
35
|
return [] unless @rules
|
36
|
+
|
34
37
|
relevant = possible_relevant_rules(subject).select do |rule|
|
35
38
|
rule.expanded_actions = expand_actions(rule.actions)
|
36
39
|
rule.relevant? action, subject
|
@@ -53,19 +56,23 @@ module CanCan
|
|
53
56
|
def relevant_rules_for_match(action, subject)
|
54
57
|
relevant_rules(action, subject).each do |rule|
|
55
58
|
next unless rule.only_raw_sql?
|
59
|
+
|
56
60
|
raise Error,
|
57
61
|
"The can? and cannot? call cannot be used with a raw sql 'can' definition."\
|
58
|
-
|
62
|
+
" The checking code cannot be determined for #{action.inspect} #{subject.inspect}"
|
59
63
|
end
|
60
64
|
end
|
61
65
|
|
62
66
|
def relevant_rules_for_query(action, subject)
|
63
|
-
relevant_rules(action, subject).
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
67
|
+
rules = relevant_rules(action, subject).reject do |rule|
|
68
|
+
# reject 'cannot' rules with attributes when doing queries
|
69
|
+
rule.base_behavior == false && rule.attributes.present?
|
70
|
+
end
|
71
|
+
if rules.any?(&:only_block?)
|
72
|
+
raise Error, "The accessible_by call cannot be used with a block 'can' definition."\
|
73
|
+
"The SQL cannot be determined for #{action.inspect} #{subject.inspect}"
|
68
74
|
end
|
75
|
+
rules
|
69
76
|
end
|
70
77
|
|
71
78
|
# Optimizes the order of the rules, so that rules with the :all subject are evaluated first.
|
@@ -75,6 +82,7 @@ module CanCan
|
|
75
82
|
(first_can_in_group = -1) && next unless rule.base_behavior
|
76
83
|
(first_can_in_group = i) && next if first_can_in_group == -1
|
77
84
|
next unless rule.subjects == [:all]
|
85
|
+
|
78
86
|
rules[i] = rules[first_can_in_group]
|
79
87
|
rules[first_can_in_group] = rule
|
80
88
|
first_can_in_group += 1
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CanCan
|
4
|
+
module Ability
|
5
|
+
module StrongParameterSupport
|
6
|
+
# Returns an array of attributes suitable for use with strong parameters
|
7
|
+
#
|
8
|
+
# Note: reversing the relevant rules is important. Normal order means that 'cannot'
|
9
|
+
# rules will come before 'can' rules. However, you can't remove attributes before
|
10
|
+
# they are added. The 'reverse' is so that attributes will be added before the
|
11
|
+
# 'cannot' rules remove them.
|
12
|
+
def permitted_attributes(action, subject)
|
13
|
+
relevant_rules(action, subject)
|
14
|
+
.reverse
|
15
|
+
.select { |rule| rule.matches_conditions? action, subject }
|
16
|
+
.each_with_object(Set.new) do |rule, set|
|
17
|
+
attributes = get_attributes(rule, subject)
|
18
|
+
# add attributes for 'can', remove them for 'cannot'
|
19
|
+
rule.base_behavior ? set.merge(attributes) : set.subtract(attributes)
|
20
|
+
end.to_a
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def subject_class?(subject)
|
26
|
+
klass = (subject.is_a?(Hash) ? subject.values.first : subject).class
|
27
|
+
[Class, Module].include? klass
|
28
|
+
end
|
29
|
+
|
30
|
+
def get_attributes(rule, subject)
|
31
|
+
klass = subject_class?(subject) ? subject : subject.class
|
32
|
+
# empty attributes is an 'all'
|
33
|
+
if rule.attributes.empty? && klass < ActiveRecord::Base
|
34
|
+
klass.column_names.map(&:to_sym) - Array(klass.primary_key)
|
35
|
+
else
|
36
|
+
rule.attributes
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# This class is responsible for matching classes and their subclasses as well as
|
2
|
+
# upmatching classes to their ancestors.
|
3
|
+
# This is used to generate sti connections
|
4
|
+
class SubjectClassMatcher
|
5
|
+
def self.matches_subject_class?(subjects, subject)
|
6
|
+
subjects.any? do |sub|
|
7
|
+
has_subclasses = subject.respond_to?(:subclasses)
|
8
|
+
matching_class_check(subject, sub, has_subclasses)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.matching_class_check(subject, sub, has_subclasses)
|
13
|
+
matches = matches_class_or_is_related(subject, sub)
|
14
|
+
if has_subclasses
|
15
|
+
matches || subject.subclasses.include?(sub)
|
16
|
+
else
|
17
|
+
matches
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.matches_class_or_is_related(subject, sub)
|
22
|
+
sub.is_a?(Module) && (subject.is_a?(sub) ||
|
23
|
+
subject.class.to_s == sub.to_s ||
|
24
|
+
(subject.is_a?(Module) && subject.ancestors.include?(sub)))
|
25
|
+
end
|
26
|
+
end
|
@@ -1,26 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CanCan
|
2
4
|
module ConditionsMatcher
|
3
5
|
# Matches the block or conditions hash
|
4
|
-
def matches_conditions?(action, subject, extra_args)
|
6
|
+
def matches_conditions?(action, subject, attribute = nil, *extra_args)
|
5
7
|
return call_block_with_all(action, subject, extra_args) if @match_all
|
6
|
-
return
|
7
|
-
matches_non_block_conditions(subject)
|
8
|
+
return matches_block_conditions(subject, attribute, *extra_args) if @block
|
9
|
+
return matches_non_block_conditions(subject) unless conditions_empty?
|
10
|
+
|
11
|
+
true
|
8
12
|
end
|
9
13
|
|
10
14
|
private
|
11
15
|
|
12
16
|
def subject_class?(subject)
|
13
17
|
klass = (subject.is_a?(Hash) ? subject.values.first : subject).class
|
14
|
-
|
18
|
+
[Class, Module].include? klass
|
19
|
+
end
|
20
|
+
|
21
|
+
def matches_block_conditions(subject, *extra_args)
|
22
|
+
return @base_behavior if subject_class?(subject)
|
23
|
+
|
24
|
+
@block.call(subject, *extra_args.compact)
|
15
25
|
end
|
16
26
|
|
17
27
|
def matches_non_block_conditions(subject)
|
18
|
-
if
|
19
|
-
|
20
|
-
|
21
|
-
end
|
28
|
+
return nested_subject_matches_conditions?(subject) if subject.class == Hash
|
29
|
+
return matches_conditions_hash?(subject) unless subject_class?(subject)
|
30
|
+
|
22
31
|
# Don't stop at "cannot" definitions when there are conditions.
|
23
|
-
|
32
|
+
@base_behavior
|
24
33
|
end
|
25
34
|
|
26
35
|
def nested_subject_matches_conditions?(subject_hash)
|
@@ -34,6 +43,7 @@ module CanCan
|
|
34
43
|
# matches_conditions_hash?(subject, conditions)
|
35
44
|
def matches_conditions_hash?(subject, conditions = @conditions)
|
36
45
|
return true if conditions.empty?
|
46
|
+
|
37
47
|
adapter = model_adapter(subject)
|
38
48
|
|
39
49
|
if adapter.override_conditions_hash_matching?(subject, conditions)
|
@@ -68,13 +78,13 @@ module CanCan
|
|
68
78
|
|
69
79
|
def hash_condition_match?(attribute, value)
|
70
80
|
if attribute.is_a?(Array) || (defined?(ActiveRecord) && attribute.is_a?(ActiveRecord::Relation))
|
71
|
-
attribute.any? { |element| matches_conditions_hash?(element, value) }
|
81
|
+
attribute.to_a.any? { |element| matches_conditions_hash?(element, value) }
|
72
82
|
else
|
73
83
|
attribute && matches_conditions_hash?(attribute, value)
|
74
84
|
end
|
75
85
|
end
|
76
86
|
|
77
|
-
def call_block_with_all(action, subject, extra_args)
|
87
|
+
def call_block_with_all(action, subject, *extra_args)
|
78
88
|
if subject.class == Class
|
79
89
|
@block.call(action, subject, nil, *extra_args)
|
80
90
|
else
|
@@ -87,7 +97,10 @@ module CanCan
|
|
87
97
|
end
|
88
98
|
|
89
99
|
def conditions_empty?
|
90
|
-
@conditions
|
100
|
+
# @conditions might be an ActiveRecord::Associations::CollectionProxy
|
101
|
+
# which it's `==` implementation will fetch all records for comparison
|
102
|
+
|
103
|
+
(@conditions.is_a?(Hash) && @conditions == {}) || @conditions.nil?
|
91
104
|
end
|
92
105
|
end
|
93
106
|
end
|