Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 147 lines (128 sloc) 5.527 kb
bbbc8a6 @ryanb refactoring much of Ability class into separate CanDefinition class
authored
1 module CanCan
2 # This class is used internally and should only be called through Ability.
dfd84a1 @ryanb improving inline documentation
authored
3 # it holds the information about a "can" call made on Ability and provides
4 # helpful methods to determine permission checking and conditions hash generation.
37c1491 @ryanb renaming CanDefinition to Rule
authored
5 class Rule # :nodoc:
f9b181a @ryanb allow Active Record scope to be passed as Ability conditions - closes #2...
authored
6 attr_reader :base_behavior, :subjects, :actions, :conditions
cad4259 @ryanb supporting deeply nested aliases - closes #98
authored
7 attr_writer :expanded_actions
5d8f043 @ryanb merging with master and resolving a couple conflicts
authored
8
dfd84a1 @ryanb improving inline documentation
authored
9 # The first argument when initializing is the base_behavior which is a true/false
10 # value. True for "can" and false for "cannot". The next two arguments are the action
11 # and subject respectively (such as :read, @project). The third argument is a hash
12 # of conditions and the last one is the block passed to the "can" call.
bbbc8a6 @ryanb refactoring much of Ability class into separate CanDefinition class
authored
13 def initialize(base_behavior, action, subject, conditions, block)
0de43c4 @ryanb raise an error when trying to make a rule with both hash conditions and ...
authored
14 raise Error, "You are not able to supply a block with a hash of conditions in #{action} #{subject} ability. Use either one." if conditions.kind_of?(Hash) && !block.nil?
66314a8 @ryanb support no arguments to 'can' definition which always calls block
authored
15 @match_all = action.nil? && subject.nil?
bbbc8a6 @ryanb refactoring much of Ability class into separate CanDefinition class
authored
16 @base_behavior = base_behavior
17 @actions = [action].flatten
18 @subjects = [subject].flatten
7543eed fixing issue when using accessible_by with nil can conditions - closes #...
John Allison authored
19 @conditions = conditions || {}
bbbc8a6 @ryanb refactoring much of Ability class into separate CanDefinition class
authored
20 @block = block
21 end
dfd84a1 @ryanb improving inline documentation
authored
22
6084814 @ryanb refactoring can definition matching behavior
authored
23 # Matches both the subject and action, not necessarily the conditions
24 def relevant?(action, subject)
f23bbe0 @spohlenz Fix rule check on Hash-like subjects
spohlenz authored
25 subject = subject.values.first if subject.class == Hash
66314a8 @ryanb support no arguments to 'can' definition which always calls block
authored
26 @match_all || (matches_action?(action) && matches_subject?(subject))
bbbc8a6 @ryanb refactoring much of Ability class into separate CanDefinition class
authored
27 end
dfd84a1 @ryanb improving inline documentation
authored
28
6084814 @ryanb refactoring can definition matching behavior
authored
29 # Matches the block or conditions hash
30 def matches_conditions?(action, subject, extra_args)
66314a8 @ryanb support no arguments to 'can' definition which always calls block
authored
31 if @match_all
32 call_block_with_all(action, subject, extra_args)
c88cb8f @ryanb passing a hash to can? will check permissions on association, this is do...
authored
33 elsif @block && !subject_class?(subject)
b1fb179 @ryanb don't pass action into can block with :manage option - closes #129
authored
34 @block.call(subject, *extra_args)
f23bbe0 @spohlenz Fix rule check on Hash-like subjects
spohlenz authored
35 elsif @conditions.kind_of?(Hash) && subject.class == Hash
c88cb8f @ryanb passing a hash to can? will check permissions on association, this is do...
authored
36 nested_subject_matches_conditions?(subject)
37 elsif @conditions.kind_of?(Hash) && !subject_class?(subject)
6084814 @ryanb refactoring can definition matching behavior
authored
38 matches_conditions_hash?(subject)
39 else
8f49f28 @ryanb don't stop at cannot definitions when there are no conditions - closes #...
authored
40 # Don't stop at "cannot" definitions when there are conditions.
41 @conditions.empty? ? true : @base_behavior
6084814 @ryanb refactoring can definition matching behavior
authored
42 end
bbbc8a6 @ryanb refactoring much of Ability class into separate CanDefinition class
authored
43 end
e200814 @ryanb adding joins clause to accessible_by when conditions are across associat...
authored
44
b473d88 CanDefinition#only_block?
Yura Sokolov authored
45 def only_block?
46 conditions_empty? && !@block.nil?
47 end
b0cec52 @ryanb adding a couple things to the changelog
authored
48
12037d7 @funny-falcon should not allow to can? when raw sql without block is present
funny-falcon authored
49 def only_raw_sql?
50 @block.nil? && !conditions_empty? && !@conditions.kind_of?(Hash)
51 end
dbc1538 small refactoring: CanDefinition #definitive? #conditions_empty?
Yura Sokolov authored
52
53 def conditions_empty?
54 @conditions == {} || @conditions.nil?
55 end
56
c27ead5 @andhapp Fix to handle MetaWhere and non-MetaWhere conditions correctly.
andhapp authored
57 def unmergeable?
58 @conditions.respond_to?(:keys) && (! @conditions.keys.first.kind_of? Symbol)
59 end
60
ba8cb3c @ryanb refactoring query.joins
authored
61 def associations_hash(conditions = @conditions)
62 hash = {}
63 conditions.map do |name, value|
64 hash[name] = associations_hash(value) if value.kind_of? Hash
f236b1b @funny-falcon resolve issue 149
funny-falcon authored
65 end if conditions.kind_of? Hash
ba8cb3c @ryanb refactoring query.joins
authored
66 hash
e200814 @ryanb adding joins clause to accessible_by when conditions are across associat...
authored
67 end
dfd84a1 @ryanb improving inline documentation
authored
68
721939b @ryanb cleaning up some internal specs and names
authored
69 def attributes_from_conditions
a744377 @ryanb the new and create actions will now build the resource with attributes b...
authored
70 attributes = {}
71 @conditions.each do |key, value|
72 attributes[key] = value unless [Array, Range, Hash].include? value.class
a0f73fe @funny-falcon fix error
funny-falcon authored
73 end if @conditions.kind_of? Hash
a744377 @ryanb the new and create actions will now build the resource with attributes b...
authored
74 attributes
75 end
76
bbbc8a6 @ryanb refactoring much of Ability class into separate CanDefinition class
authored
77 private
dfd84a1 @ryanb improving inline documentation
authored
78
c88cb8f @ryanb passing a hash to can? will check permissions on association, this is do...
authored
79 def subject_class?(subject)
ebef3cc @funny-falcon consistency addition for ability check on Module
funny-falcon authored
80 klass = (subject.kind_of?(Hash) ? subject.values.first : subject).class
81 klass == Class || klass == Module
c88cb8f @ryanb passing a hash to can? will check permissions on association, this is do...
authored
82 end
83
bbbc8a6 @ryanb refactoring much of Ability class into separate CanDefinition class
authored
84 def matches_action?(action)
85 @expanded_actions.include?(:manage) || @expanded_actions.include?(action)
86 end
dfd84a1 @ryanb improving inline documentation
authored
87
bbbc8a6 @ryanb refactoring much of Ability class into separate CanDefinition class
authored
88 def matches_subject?(subject)
961b8c2 @ryanb consider ancestors when matching classes in Ability#can, this way it wor...
authored
89 @subjects.include?(:all) || @subjects.include?(subject) || matches_subject_class?(subject)
90 end
91
92 def matches_subject_class?(subject)
79180de @mphalliday This fixes an odd error I was seeing in development mode when cache_clas...
mphalliday authored
93 @subjects.any? { |sub| sub.kind_of?(Module) && (subject.kind_of?(sub) || subject.class.to_s == sub.to_s || subject.kind_of?(Module) && subject.ancestors.include?(sub)) }
bbbc8a6 @ryanb refactoring much of Ability class into separate CanDefinition class
authored
94 end
dfd84a1 @ryanb improving inline documentation
authored
95
cef6c21 @ryanb allow model adapter to override condition hash matching in Rule, also cl...
authored
96 # Checks if the given subject matches the given conditions hash.
97 # This behavior can be overriden by a model adapter by defining two class methods:
98 # override_matching_for_conditions?(subject, conditions) and
99 # matches_conditions_hash?(subject, conditions)
6084814 @ryanb refactoring can definition matching behavior
authored
100 def matches_conditions_hash?(subject, conditions = @conditions)
cef6c21 @ryanb allow model adapter to override condition hash matching in Rule, also cl...
authored
101 if conditions.empty?
102 true
103 else
104 if model_adapter(subject).override_conditions_hash_matching? subject, conditions
105 model_adapter(subject).matches_conditions_hash? subject, conditions
bbbc8a6 @ryanb refactoring much of Ability class into separate CanDefinition class
authored
106 else
cef6c21 @ryanb allow model adapter to override condition hash matching in Rule, also cl...
authored
107 conditions.all? do |name, value|
ff5aaf5 @ryanb adding initial MetaWhere support
authored
108 if model_adapter(subject).override_condition_matching? subject, name, value
109 model_adapter(subject).matches_condition? subject, name, value
110 else
111 attribute = subject.send(name)
112 if value.kind_of?(Hash)
113 if attribute.kind_of? Array
114 attribute.any? { |element| matches_conditions_hash? element, value }
115 else
6aaab9e @thatothermitch Fixed bug where conditions on an optionally associated object would thro...
thatothermitch authored
116 !attribute.nil? && matches_conditions_hash?(attribute, value)
ff5aaf5 @ryanb adding initial MetaWhere support
authored
117 end
65bbf0e @Aryk Add check for Enumerable as condition value
Aryk authored
118 elsif value.kind_of?(Enumerable)
ff5aaf5 @ryanb adding initial MetaWhere support
authored
119 value.include? attribute
cef6c21 @ryanb allow model adapter to override condition hash matching in Rule, also cl...
authored
120 else
ff5aaf5 @ryanb adding initial MetaWhere support
authored
121 attribute == value
cef6c21 @ryanb allow model adapter to override condition hash matching in Rule, also cl...
authored
122 end
123 end
124 end
bbbc8a6 @ryanb refactoring much of Ability class into separate CanDefinition class
authored
125 end
126 end
127 end
a5f838a @ryanb use I18n for unauthorization messages - closes #103
authored
128
c88cb8f @ryanb passing a hash to can? will check permissions on association, this is do...
authored
129 def nested_subject_matches_conditions?(subject_hash)
ba01349 @flop Don't remove key-value from the subject hash we might want to use it aga...
flop authored
130 parent, child = subject_hash.first
1be5bf7 @ryanb don't fail if association conditions aren't specified for nested associa...
authored
131 matches_conditions_hash?(parent, @conditions[parent.class.name.downcase.to_sym] || {})
c88cb8f @ryanb passing a hash to can? will check permissions on association, this is do...
authored
132 end
133
66314a8 @ryanb support no arguments to 'can' definition which always calls block
authored
134 def call_block_with_all(action, subject, extra_args)
135 if subject.class == Class
136 @block.call(action, subject, nil, *extra_args)
137 else
138 @block.call(action, subject.class, subject, *extra_args)
139 end
140 end
cef6c21 @ryanb allow model adapter to override condition hash matching in Rule, also cl...
authored
141
142 def model_adapter(subject)
80ceaf8 @soopa fix uninitialized constant warning in CanCan::Rule#model_adapter
soopa authored
143 CanCan::ModelAdapters::AbstractAdapter.adapter_class(subject_class?(subject) ? subject : subject.class)
cef6c21 @ryanb allow model adapter to override condition hash matching in Rule, also cl...
authored
144 end
bbbc8a6 @ryanb refactoring much of Ability class into separate CanDefinition class
authored
145 end
146 end
Something went wrong with that request. Please try again.