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.
- checksums.yaml +4 -4
- data/lib/cancan.rb +1 -1
- data/lib/cancan/ability.rb +13 -175
- data/lib/cancan/ability/actions.rb +91 -0
- data/lib/cancan/ability/rules.rb +85 -0
- data/lib/cancan/conditions_matcher.rb +93 -0
- data/lib/cancan/controller_resource.rb +22 -207
- data/lib/cancan/controller_resource_builder.rb +24 -0
- data/lib/cancan/controller_resource_finder.rb +35 -0
- data/lib/cancan/controller_resource_loader.rb +116 -0
- data/lib/cancan/controller_resource_name_finder.rb +21 -0
- data/lib/cancan/controller_resource_sanitizer.rb +30 -0
- data/lib/cancan/model_adapters/active_record_adapter.rb +55 -70
- data/lib/cancan/model_adapters/can_can/model_adapters/active_record_adapter/joins.rb +39 -0
- data/lib/cancan/rule.rb +4 -83
- data/lib/cancan/version.rb +1 -1
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a754d91858c1b6c433c9b7c12d6b4e99440c0cc0
|
4
|
+
data.tar.gz: 31d2172742361e8a5ee8e7d74d2d5ca3a8e0e681
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a15feefdba0ac03be2609772608006b2a4546d8ce5bcfd1e1a656a136ad87c837a2b3506bc57c8ae57747b47c6464d4e5912c5252c41b5acc4f625a3aaa01bc
|
7
|
+
data.tar.gz: 6492f1fd59db034738c473a7c25677037d7ab37aabb644b4cffb057ed97e53519e25c9aa90d7048f2485088859094824af9dad7926d0ec27d3e2ff20b331ba33
|
data/lib/cancan.rb
CHANGED
@@ -10,6 +10,6 @@ require 'cancan/model_adapters/abstract_adapter'
|
|
10
10
|
require 'cancan/model_adapters/default_adapter'
|
11
11
|
|
12
12
|
if defined? ActiveRecord
|
13
|
-
require 'cancan/model_adapters/active_record_adapter'
|
13
|
+
require 'cancan/model_adapters/active_record_adapter'
|
14
14
|
require 'cancan/model_adapters/active_record_4_adapter'
|
15
15
|
end
|
data/lib/cancan/ability.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require_relative 'ability/rules.rb'
|
2
|
+
require_relative 'ability/actions.rb'
|
1
3
|
module CanCan
|
2
4
|
# This module is designed to be included into an Ability class. This will
|
3
5
|
# provide the "can" methods for defining and checking abilities.
|
@@ -15,6 +17,9 @@ module CanCan
|
|
15
17
|
# end
|
16
18
|
#
|
17
19
|
module Ability
|
20
|
+
include CanCan::Ability::Rules
|
21
|
+
include CanCan::Ability::Actions
|
22
|
+
|
18
23
|
# Check if the user has permission to perform a given action on an object.
|
19
24
|
#
|
20
25
|
# can? :destroy, @project
|
@@ -149,58 +154,12 @@ module CanCan
|
|
149
154
|
add_rule(Rule.new(false, action, subject, conditions, block))
|
150
155
|
end
|
151
156
|
|
152
|
-
# Alias one or more actions into another one.
|
153
|
-
#
|
154
|
-
# alias_action :update, :destroy, :to => :modify
|
155
|
-
# can :modify, Comment
|
156
|
-
#
|
157
|
-
# Then :modify permission will apply to both :update and :destroy requests.
|
158
|
-
#
|
159
|
-
# can? :update, Comment # => true
|
160
|
-
# can? :destroy, Comment # => true
|
161
|
-
#
|
162
|
-
# This only works in one direction. Passing the aliased action into the "can?" call
|
163
|
-
# will not work because aliases are meant to generate more generic actions.
|
164
|
-
#
|
165
|
-
# alias_action :update, :destroy, :to => :modify
|
166
|
-
# can :update, Comment
|
167
|
-
# can? :modify, Comment # => false
|
168
|
-
#
|
169
|
-
# Unless that exact alias is used.
|
170
|
-
#
|
171
|
-
# can :modify, Comment
|
172
|
-
# can? :modify, Comment # => true
|
173
|
-
#
|
174
|
-
# The following aliases are added by default for conveniently mapping common controller actions.
|
175
|
-
#
|
176
|
-
# alias_action :index, :show, :to => :read
|
177
|
-
# alias_action :new, :to => :create
|
178
|
-
# alias_action :edit, :to => :update
|
179
|
-
#
|
180
|
-
# This way one can use params[:action] in the controller to determine the permission.
|
181
|
-
def alias_action(*args)
|
182
|
-
target = args.pop[:to]
|
183
|
-
validate_target(target)
|
184
|
-
aliased_actions[target] ||= []
|
185
|
-
aliased_actions[target] += args
|
186
|
-
end
|
187
|
-
|
188
157
|
# User shouldn't specify targets with names of real actions or it will cause Seg fault
|
189
158
|
def validate_target(target)
|
190
159
|
error_message = "You can't specify target (#{target}) as alias because it is real action name"
|
191
160
|
raise Error, error_message if aliased_actions.values.flatten.include? target
|
192
161
|
end
|
193
162
|
|
194
|
-
# Returns a hash of aliased actions. The key is the target and the value is an array of actions aliasing the key.
|
195
|
-
def aliased_actions
|
196
|
-
@aliased_actions ||= default_alias_actions
|
197
|
-
end
|
198
|
-
|
199
|
-
# Removes previously aliased actions including the defaults.
|
200
|
-
def clear_aliased_actions
|
201
|
-
@aliased_actions = {}
|
202
|
-
end
|
203
|
-
|
204
163
|
def model_adapter(model_class, action)
|
205
164
|
adapter_class = ModelAdapters::AbstractAdapter.adapter_class(model_class)
|
206
165
|
adapter_class.new(model_class, relevant_rules_for_query(action, model_class))
|
@@ -262,29 +221,16 @@ module CanCan
|
|
262
221
|
# }
|
263
222
|
def permissions
|
264
223
|
permissions_list = { can: {}, cannot: {} }
|
265
|
-
|
266
|
-
rules.each do |rule|
|
267
|
-
subjects = rule.subjects
|
268
|
-
expand_actions(rule.actions).each do |action|
|
269
|
-
if rule.base_behavior
|
270
|
-
permissions_list[:can][action] ||= []
|
271
|
-
permissions_list[:can][action] += subjects.map(&:to_s)
|
272
|
-
else
|
273
|
-
permissions_list[:cannot][action] ||= []
|
274
|
-
permissions_list[:cannot][action] += subjects.map(&:to_s)
|
275
|
-
end
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
224
|
+
rules.each { |rule| extract_rule_in_permissions(permissions_list, rule) }
|
279
225
|
permissions_list
|
280
226
|
end
|
281
227
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
228
|
+
def extract_rule_in_permissions(permissions_list, rule)
|
229
|
+
expand_actions(rule.actions).each do |action|
|
230
|
+
container = rule.base_behavior ? :can : :cannot
|
231
|
+
permissions_list[container][action] ||= []
|
232
|
+
permissions_list[container][action] += rule.subjects.map(&:to_s)
|
233
|
+
end
|
288
234
|
end
|
289
235
|
|
290
236
|
private
|
@@ -297,26 +243,6 @@ module CanCan
|
|
297
243
|
end
|
298
244
|
end
|
299
245
|
|
300
|
-
# Accepts an array of actions and returns an array of actions which match.
|
301
|
-
# This should be called before "matches?" and other checking methods since they
|
302
|
-
# rely on the actions to be expanded.
|
303
|
-
def expand_actions(actions)
|
304
|
-
expanded_actions[actions] ||= begin
|
305
|
-
expanded = []
|
306
|
-
actions.each do |action|
|
307
|
-
expanded << action
|
308
|
-
if (aliases = aliased_actions[action])
|
309
|
-
expanded += expand_actions(aliases)
|
310
|
-
end
|
311
|
-
end
|
312
|
-
expanded
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
def expanded_actions
|
317
|
-
@expanded_actions ||= {}
|
318
|
-
end
|
319
|
-
|
320
246
|
# It translates to an array the subject or the hash with multiple subjects given to can?.
|
321
247
|
def extract_subjects(subject)
|
322
248
|
if subject.is_a?(Hash) && subject.key?(:any)
|
@@ -326,97 +252,9 @@ module CanCan
|
|
326
252
|
end
|
327
253
|
end
|
328
254
|
|
329
|
-
# Given an action, it will try to find all of the actions which are aliased to it.
|
330
|
-
# This does the opposite kind of lookup as expand_actions.
|
331
|
-
def aliases_for_action(action)
|
332
|
-
results = [action]
|
333
|
-
aliased_actions.each do |aliased_action, actions|
|
334
|
-
results += aliases_for_action(aliased_action) if actions.include? action
|
335
|
-
end
|
336
|
-
results
|
337
|
-
end
|
338
|
-
|
339
|
-
def add_rule(rule)
|
340
|
-
rules << rule
|
341
|
-
add_rule_to_index(rule, rules.size - 1)
|
342
|
-
end
|
343
|
-
|
344
|
-
def add_rule_to_index(rule, position)
|
345
|
-
@rules_index ||= Hash.new { |h, k| h[k] = [] }
|
346
|
-
|
347
|
-
subjects = rule.subjects.compact
|
348
|
-
subjects << :all if subjects.empty?
|
349
|
-
|
350
|
-
subjects.each do |subject|
|
351
|
-
@rules_index[subject] << position
|
352
|
-
end
|
353
|
-
end
|
354
|
-
|
355
255
|
def alternative_subjects(subject)
|
356
256
|
subject = subject.class unless subject.is_a?(Module)
|
357
|
-
[:all, *subject.ancestors,
|
358
|
-
end
|
359
|
-
|
360
|
-
# Returns an array of Rule instances which match the action and subject
|
361
|
-
# This does not take into consideration any hash conditions or block statements
|
362
|
-
def relevant_rules(action, subject)
|
363
|
-
return [] unless @rules
|
364
|
-
relevant = possible_relevant_rules(subject).select do |rule|
|
365
|
-
rule.expanded_actions = expand_actions(rule.actions)
|
366
|
-
rule.relevant? action, subject
|
367
|
-
end
|
368
|
-
relevant.reverse!.uniq!
|
369
|
-
optimize_order! relevant
|
370
|
-
relevant
|
371
|
-
end
|
372
|
-
|
373
|
-
# Optimizes the order of the rules, so that rules with the :all subject are evaluated first.
|
374
|
-
def optimize_order!(rules)
|
375
|
-
first_can_in_group = -1
|
376
|
-
rules.each_with_index do |rule, i|
|
377
|
-
(first_can_in_group = -1) && next unless rule.base_behavior
|
378
|
-
(first_can_in_group = i) && next if first_can_in_group == -1
|
379
|
-
next unless rule.subjects == [:all]
|
380
|
-
rules[i] = rules[first_can_in_group]
|
381
|
-
rules[first_can_in_group] = rule
|
382
|
-
first_can_in_group += 1
|
383
|
-
end
|
384
|
-
end
|
385
|
-
|
386
|
-
def possible_relevant_rules(subject)
|
387
|
-
if subject.is_a?(Hash)
|
388
|
-
rules
|
389
|
-
else
|
390
|
-
positions = @rules_index.values_at(subject, *alternative_subjects(subject))
|
391
|
-
positions.flatten!.sort!
|
392
|
-
positions.map { |i| @rules[i] }
|
393
|
-
end
|
394
|
-
end
|
395
|
-
|
396
|
-
def relevant_rules_for_match(action, subject)
|
397
|
-
relevant_rules(action, subject).each do |rule|
|
398
|
-
next unless rule.only_raw_sql?
|
399
|
-
raise Error,
|
400
|
-
"The can? and cannot? call cannot be used with a raw sql 'can' definition."\
|
401
|
-
" The checking code cannot be determined for #{action.inspect} #{subject.inspect}"
|
402
|
-
end
|
403
|
-
end
|
404
|
-
|
405
|
-
def relevant_rules_for_query(action, subject)
|
406
|
-
relevant_rules(action, subject).each do |rule|
|
407
|
-
if rule.only_block?
|
408
|
-
raise Error, "The accessible_by call cannot be used with a block 'can' definition."\
|
409
|
-
" The SQL cannot be determined for #{action.inspect} #{subject.inspect}"
|
410
|
-
end
|
411
|
-
end
|
412
|
-
end
|
413
|
-
|
414
|
-
def default_alias_actions
|
415
|
-
{
|
416
|
-
read: %i[index show],
|
417
|
-
create: [:new],
|
418
|
-
update: [:edit]
|
419
|
-
}
|
257
|
+
[:all, *subject.ancestors, subject.class.to_s]
|
420
258
|
end
|
421
259
|
end
|
422
260
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module CanCan
|
2
|
+
module Ability
|
3
|
+
module Actions
|
4
|
+
# Alias one or more actions into another one.
|
5
|
+
#
|
6
|
+
# alias_action :update, :destroy, :to => :modify
|
7
|
+
# can :modify, Comment
|
8
|
+
#
|
9
|
+
# Then :modify permission will apply to both :update and :destroy requests.
|
10
|
+
#
|
11
|
+
# can? :update, Comment # => true
|
12
|
+
# can? :destroy, Comment # => true
|
13
|
+
#
|
14
|
+
# This only works in one direction. Passing the aliased action into the "can?" call
|
15
|
+
# will not work because aliases are meant to generate more generic actions.
|
16
|
+
#
|
17
|
+
# alias_action :update, :destroy, :to => :modify
|
18
|
+
# can :update, Comment
|
19
|
+
# can? :modify, Comment # => false
|
20
|
+
#
|
21
|
+
# Unless that exact alias is used.
|
22
|
+
#
|
23
|
+
# can :modify, Comment
|
24
|
+
# can? :modify, Comment # => true
|
25
|
+
#
|
26
|
+
# The following aliases are added by default for conveniently mapping common controller actions.
|
27
|
+
#
|
28
|
+
# alias_action :index, :show, :to => :read
|
29
|
+
# alias_action :new, :to => :create
|
30
|
+
# alias_action :edit, :to => :update
|
31
|
+
#
|
32
|
+
# This way one can use params[:action] in the controller to determine the permission.
|
33
|
+
def alias_action(*args)
|
34
|
+
target = args.pop[:to]
|
35
|
+
validate_target(target)
|
36
|
+
aliased_actions[target] ||= []
|
37
|
+
aliased_actions[target] += args
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns a hash of aliased actions. The key is the target and the value is an array of actions aliasing the key.
|
41
|
+
def aliased_actions
|
42
|
+
@aliased_actions ||= default_alias_actions
|
43
|
+
end
|
44
|
+
|
45
|
+
# Removes previously aliased actions including the defaults.
|
46
|
+
def clear_aliased_actions
|
47
|
+
@aliased_actions = {}
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def default_alias_actions
|
53
|
+
{
|
54
|
+
read: %i[index show],
|
55
|
+
create: [:new],
|
56
|
+
update: [:edit]
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
# Given an action, it will try to find all of the actions which are aliased to it.
|
61
|
+
# This does the opposite kind of lookup as expand_actions.
|
62
|
+
def aliases_for_action(action)
|
63
|
+
results = [action]
|
64
|
+
aliased_actions.each do |aliased_action, actions|
|
65
|
+
results += aliases_for_action(aliased_action) if actions.include? action
|
66
|
+
end
|
67
|
+
results
|
68
|
+
end
|
69
|
+
|
70
|
+
def expanded_actions
|
71
|
+
@expanded_actions ||= {}
|
72
|
+
end
|
73
|
+
|
74
|
+
# Accepts an array of actions and returns an array of actions which match.
|
75
|
+
# This should be called before "matches?" and other checking methods since they
|
76
|
+
# rely on the actions to be expanded.
|
77
|
+
def expand_actions(actions)
|
78
|
+
expanded_actions[actions] ||= begin
|
79
|
+
expanded = []
|
80
|
+
actions.each do |action|
|
81
|
+
expanded << action
|
82
|
+
if (aliases = aliased_actions[action])
|
83
|
+
expanded += expand_actions(aliases)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
expanded
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module CanCan
|
2
|
+
module Ability
|
3
|
+
module Rules
|
4
|
+
protected
|
5
|
+
|
6
|
+
# Must be protected as an ability can merge with other abilities.
|
7
|
+
# This means that an ability must expose their rules with another ability.
|
8
|
+
def rules
|
9
|
+
@rules ||= []
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def add_rule(rule)
|
15
|
+
rules << rule
|
16
|
+
add_rule_to_index(rule, rules.size - 1)
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_rule_to_index(rule, position)
|
20
|
+
@rules_index ||= Hash.new { |h, k| h[k] = [] }
|
21
|
+
|
22
|
+
subjects = rule.subjects.compact
|
23
|
+
subjects << :all if subjects.empty?
|
24
|
+
|
25
|
+
subjects.each do |subject|
|
26
|
+
@rules_index[subject] << position
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns an array of Rule instances which match the action and subject
|
31
|
+
# This does not take into consideration any hash conditions or block statements
|
32
|
+
def relevant_rules(action, subject)
|
33
|
+
return [] unless @rules
|
34
|
+
relevant = possible_relevant_rules(subject).select do |rule|
|
35
|
+
rule.expanded_actions = expand_actions(rule.actions)
|
36
|
+
rule.relevant? action, subject
|
37
|
+
end
|
38
|
+
relevant.reverse!.uniq!
|
39
|
+
optimize_order! relevant
|
40
|
+
relevant
|
41
|
+
end
|
42
|
+
|
43
|
+
def possible_relevant_rules(subject)
|
44
|
+
if subject.is_a?(Hash)
|
45
|
+
rules
|
46
|
+
else
|
47
|
+
positions = @rules_index.values_at(subject, *alternative_subjects(subject))
|
48
|
+
positions.flatten!.sort!
|
49
|
+
positions.map { |i| @rules[i] }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def relevant_rules_for_match(action, subject)
|
54
|
+
relevant_rules(action, subject).each do |rule|
|
55
|
+
next unless rule.only_raw_sql?
|
56
|
+
raise Error,
|
57
|
+
"The can? and cannot? call cannot be used with a raw sql 'can' definition."\
|
58
|
+
" The checking code cannot be determined for #{action.inspect} #{subject.inspect}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def relevant_rules_for_query(action, subject)
|
63
|
+
relevant_rules(action, subject).each do |rule|
|
64
|
+
if rule.only_block?
|
65
|
+
raise Error, "The accessible_by call cannot be used with a block 'can' definition."\
|
66
|
+
" The SQL cannot be determined for #{action.inspect} #{subject.inspect}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Optimizes the order of the rules, so that rules with the :all subject are evaluated first.
|
72
|
+
def optimize_order!(rules)
|
73
|
+
first_can_in_group = -1
|
74
|
+
rules.each_with_index do |rule, i|
|
75
|
+
(first_can_in_group = -1) && next unless rule.base_behavior
|
76
|
+
(first_can_in_group = i) && next if first_can_in_group == -1
|
77
|
+
next unless rule.subjects == [:all]
|
78
|
+
rules[i] = rules[first_can_in_group]
|
79
|
+
rules[first_can_in_group] = rule
|
80
|
+
first_can_in_group += 1
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module CanCan
|
2
|
+
module ConditionsMatcher
|
3
|
+
# Matches the block or conditions hash
|
4
|
+
def matches_conditions?(action, subject, extra_args)
|
5
|
+
return call_block_with_all(action, subject, extra_args) if @match_all
|
6
|
+
return @block.call(subject, *extra_args) if @block && !subject_class?(subject)
|
7
|
+
matches_non_block_conditions(subject)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def subject_class?(subject)
|
13
|
+
klass = (subject.is_a?(Hash) ? subject.values.first : subject).class
|
14
|
+
klass == Class || klass == Module
|
15
|
+
end
|
16
|
+
|
17
|
+
def matches_non_block_conditions(subject)
|
18
|
+
if @conditions.is_a?(Hash)
|
19
|
+
return nested_subject_matches_conditions?(subject) if subject.class == Hash
|
20
|
+
return matches_conditions_hash?(subject) unless subject_class?(subject)
|
21
|
+
end
|
22
|
+
# Don't stop at "cannot" definitions when there are conditions.
|
23
|
+
conditions_empty? ? true : @base_behavior
|
24
|
+
end
|
25
|
+
|
26
|
+
def nested_subject_matches_conditions?(subject_hash)
|
27
|
+
parent, _child = subject_hash.first
|
28
|
+
matches_conditions_hash?(parent, @conditions[parent.class.name.downcase.to_sym] || {})
|
29
|
+
end
|
30
|
+
|
31
|
+
# Checks if the given subject matches the given conditions hash.
|
32
|
+
# This behavior can be overriden by a model adapter by defining two class methods:
|
33
|
+
# override_matching_for_conditions?(subject, conditions) and
|
34
|
+
# matches_conditions_hash?(subject, conditions)
|
35
|
+
def matches_conditions_hash?(subject, conditions = @conditions)
|
36
|
+
return true if conditions.empty?
|
37
|
+
adapter = model_adapter(subject)
|
38
|
+
|
39
|
+
if adapter.override_conditions_hash_matching?(subject, conditions)
|
40
|
+
return adapter.matches_conditions_hash?(subject, conditions)
|
41
|
+
end
|
42
|
+
|
43
|
+
matches_all_conditions?(adapter, conditions, subject)
|
44
|
+
end
|
45
|
+
|
46
|
+
def matches_all_conditions?(adapter, conditions, subject)
|
47
|
+
conditions.all? do |name, value|
|
48
|
+
if adapter.override_condition_matching?(subject, name, value)
|
49
|
+
adapter.matches_condition?(subject, name, value)
|
50
|
+
else
|
51
|
+
condition_match?(subject.send(name), value)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def condition_match?(attribute, value)
|
57
|
+
case value
|
58
|
+
when Hash
|
59
|
+
hash_condition_match?(attribute, value)
|
60
|
+
when Range
|
61
|
+
value.cover?(attribute)
|
62
|
+
when Enumerable
|
63
|
+
value.include?(attribute)
|
64
|
+
else
|
65
|
+
attribute == value
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def hash_condition_match?(attribute, value)
|
70
|
+
if attribute.is_a?(Array) || (defined?(ActiveRecord) && attribute.is_a?(ActiveRecord::Relation))
|
71
|
+
attribute.any? { |element| matches_conditions_hash?(element, value) }
|
72
|
+
else
|
73
|
+
attribute && matches_conditions_hash?(attribute, value)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def call_block_with_all(action, subject, extra_args)
|
78
|
+
if subject.class == Class
|
79
|
+
@block.call(action, subject, nil, *extra_args)
|
80
|
+
else
|
81
|
+
@block.call(action, subject.class, subject, *extra_args)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def model_adapter(subject)
|
86
|
+
CanCan::ModelAdapters::AbstractAdapter.adapter_class(subject_class?(subject) ? subject : subject.class)
|
87
|
+
end
|
88
|
+
|
89
|
+
def conditions_empty?
|
90
|
+
@conditions == {} || @conditions.nil?
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|