@@ -13,13 +13,15 @@ module PhiRecord
13
13
included do
14
14
class_attribute :__phi_exclude_methods
15
15
class_attribute :__phi_include_methods
16
- class_attribute :__phi_extended_methods
16
+ class_attribute :__phi_extend_methods
17
17
class_attribute :__phi_methods_wrapped
18
+ class_attribute :__phi_methods_extended
18
19
19
20
after_initialize :wrap_phi
20
21
22
+ # These have to default to an empty array
21
23
self . __phi_methods_wrapped = [ ]
22
- self . __phi_extended_methods = [ ]
24
+ self . __phi_methods_extended = [ ]
23
25
end
24
26
25
27
class_methods do
@@ -49,15 +51,15 @@ def include_in_phi(*methods)
49
51
# is allowed. The methods that are extended should return ActiveRecord
50
52
# models that also extend PhiAttrs.
51
53
#
52
- # If they do not, this is essentially an alias for PhiRecord#include_in_phi
53
- #
54
54
# @param [Array<Symbol>] *methods Any number of methods to extend access to
55
55
#
56
56
# @example
57
+ # has_one :foo
58
+ # has_one :bar
57
59
# extend_phi_access :foo, :bar
58
60
#
59
61
def extend_phi_access ( *methods )
60
- self . __phi_extended_methods = methods . map ( &:to_s )
62
+ self . __phi_extend_methods = methods . map ( &:to_s )
61
63
end
62
64
63
65
# Enable PHI access for any instance of this class.
@@ -100,11 +102,18 @@ def disallow_phi!
100
102
# @return [Array<String>] the method names to be wrapped with PHI access logging
101
103
#
102
104
def __phi_wrapped_methods
103
- extended_methods = self . class . __phi_extended_methods . to_a
104
105
excluded_methods = self . class . __phi_exclude_methods . to_a
105
106
included_methods = self . class . __phi_include_methods . to_a
106
107
107
- extended_methods + attribute_names - excluded_methods + included_methods - [ self . class . primary_key ]
108
+ attribute_names - excluded_methods + included_methods - [ self . class . primary_key ]
109
+ end
110
+
111
+ # Get all method names to be wrapped with PHI access extension
112
+ #
113
+ # @return [Array<String>] the method names to be wrapped with PHI access extension
114
+ #
115
+ def __phi_extended_methods
116
+ self . class . __phi_extend_methods . to_a
108
117
end
109
118
110
119
# Enable PHI access for a single instance of this class.
@@ -167,7 +176,8 @@ def wrap_phi
167
176
@__phi_access_logged = false
168
177
169
178
# Wrap attributes with PHI Logger and Access Control
170
- __phi_wrapped_methods . each { |attr | phi_wrap_method ( attr ) }
179
+ __phi_wrapped_methods . each { |m | phi_wrap_method ( m ) }
180
+ __phi_extended_methods . each { |m | phi_extend_access ( m ) }
171
181
end
172
182
173
183
# Log Key for an instance of this class. If the instance is persisted in the
@@ -255,26 +265,46 @@ def phi_wrap_method(method_name)
255
265
@__phi_access_logged = true
256
266
end
257
267
258
- # extend PHI access to relationships if needed
259
- if self . class . __phi_extended_methods . include? method_name
268
+ send ( unwrapped_method , *args , &block )
269
+ end
270
+ end
260
271
261
- # get the unwrapped relation
262
- relation = send ( unwrapped_method , *args , &block )
272
+ # method_name => wrapped_method => unwrapped_method
273
+ self . class . send ( :alias_method , unwrapped_method , method_name )
274
+ self . class . send ( :alias_method , method_name , wrapped_method )
263
275
264
- if relation . class . included_modules . include? ( PhiRecord )
265
- relation . allow_phi! ( phi_allowed_by , phi_access_reason ) unless relation . phi_allowed?
266
- end
267
- end
276
+ self . class . __phi_methods_wrapped << method_name
277
+ end
268
278
269
- send ( unwrapped_method , *args , &block )
279
+ # Core logic for wrapping methods in PHI access extensions. Almost
280
+ # functionally equivalent to the phi_wrap_method call above,
281
+ # this method doesn't add any logging or access restriction, but
282
+ # simply proxies the PhiRecord#allow_phi! call.
283
+ #
284
+ # @private
285
+ #
286
+ def phi_extend_access ( method_name )
287
+ return if self . class . __phi_methods_extended . include? method_name
288
+
289
+ wrapped_method = :"__#{ method_name } _phi_access_extended"
290
+ unwrapped_method = :"__#{ method_name } _phi_access_original"
291
+
292
+ self . class . send ( :define_method , wrapped_method ) do |*args , &block |
293
+ # get the unwrapped relation
294
+ relation = send ( unwrapped_method , *args , &block )
295
+
296
+ if phi_allowed? && relation . class . included_modules . include? ( PhiRecord )
297
+ relation . allow_phi! ( phi_allowed_by , phi_access_reason ) unless relation . phi_allowed?
270
298
end
299
+
300
+ relation
271
301
end
272
302
273
303
# method_name => wrapped_method => unwrapped_method
274
304
self . class . send ( :alias_method , unwrapped_method , method_name )
275
305
self . class . send ( :alias_method , method_name , wrapped_method )
276
306
277
- self . class . __phi_methods_wrapped << method_name
307
+ self . class . __phi_methods_extended << method_name
278
308
end
279
309
end
280
310
end
0 commit comments