rubypitaya 2.14.0 → 2.18.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/lib/rubypitaya/app-template/Gemfile +6 -6
- data/lib/rubypitaya/app-template/Gemfile.lock +93 -67
- data/lib/rubypitaya/app-template/Makefile +1 -1
- data/lib/rubypitaya/app-template/app/bll/player_bll.rb +2 -2
- data/lib/rubypitaya/app-template/app/handlers/player_handler.rb +1 -1
- data/lib/rubypitaya/app-template/docker/dev/Dockerfile +10 -7
- data/lib/rubypitaya/app-template/docker/prod/Dockerfile +19 -19
- data/lib/rubypitaya/core/config.rb +23 -4
- data/lib/rubypitaya/core/config_core.rb +4 -21
- data/lib/rubypitaya/core/db/migration/0000000001_create_user_migration.rb +1 -1
- data/lib/rubypitaya/core/main.rb +7 -5
- data/lib/rubypitaya/core/parameters.rb +449 -138
- data/lib/rubypitaya/core/spec-helpers/handler_spec_helper.rb +20 -0
- data/lib/rubypitaya/core/templates/template_migration.rb.erb +1 -1
- data/lib/rubypitaya/version.rb +1 -1
- metadata +23 -23
data/lib/rubypitaya/core/main.rb
CHANGED
@@ -141,10 +141,10 @@ module RubyPitaya
|
|
141
141
|
|
142
142
|
def run_nats_connection
|
143
143
|
@nats_connector.connect do |request|
|
144
|
-
start_time_seconds = Time.now.
|
144
|
+
start_time_seconds = Time.now.to_f
|
145
145
|
|
146
146
|
message_route = request[:msg][:route]
|
147
|
-
message_data = request[:msg][:data]
|
147
|
+
message_data = request[:msg][:data] || {}
|
148
148
|
message_data = JSON.parse(message_data) if message_data.class == String
|
149
149
|
|
150
150
|
params = Parameters.new(message_data)
|
@@ -165,19 +165,21 @@ module RubyPitaya
|
|
165
165
|
@log.info "request -> route: #{message_route}"
|
166
166
|
@log.info " -> data: #{message_data}"
|
167
167
|
|
168
|
+
@config.clear_cache
|
169
|
+
|
168
170
|
response = @handler_router.call(handler_name, action_name, @session,
|
169
171
|
@postman, @redis_connector.redis,
|
170
172
|
@setup, @config, @bll, @log, params)
|
171
173
|
|
172
|
-
delta_time_seconds = Time.now.
|
174
|
+
delta_time_seconds = ((Time.now.to_f - start_time_seconds) * 1000).round(2)
|
173
175
|
|
174
|
-
@log.info "response [#{delta_time_seconds}
|
176
|
+
@log.info "response [#{delta_time_seconds}ms] -> #{response.to_json}"
|
175
177
|
|
176
178
|
response
|
177
179
|
end
|
178
180
|
rescue Exception => error
|
179
181
|
@log.info "ERROR: #{error}"
|
180
|
-
@log.info error.backtrace
|
182
|
+
@log.info error.backtrace.join("\n")
|
181
183
|
run_nats_connection
|
182
184
|
end
|
183
185
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'date'
|
2
|
+
require 'yaml'
|
2
3
|
require 'bigdecimal'
|
3
4
|
require 'stringio'
|
4
5
|
|
@@ -9,12 +10,36 @@ require 'active_support/core_ext/array/wrap'
|
|
9
10
|
module RubyPitaya
|
10
11
|
|
11
12
|
class ParameterMissing < IndexError
|
12
|
-
attr_reader :param
|
13
|
+
attr_reader :param, :keys
|
13
14
|
|
14
|
-
def initialize(param)
|
15
|
+
def initialize(param, keys = nil)
|
15
16
|
@param = param
|
17
|
+
@keys = keys
|
16
18
|
super("param is missing or the value is empty: #{param}")
|
17
19
|
end
|
20
|
+
|
21
|
+
class Correction
|
22
|
+
def initialize(error)
|
23
|
+
@error = error
|
24
|
+
end
|
25
|
+
|
26
|
+
def corrections
|
27
|
+
if @error.param && @error.keys
|
28
|
+
maybe_these = @error.keys
|
29
|
+
|
30
|
+
maybe_these.sort_by { |n|
|
31
|
+
DidYouMean::Jaro.distance(@error.param.to_s, n)
|
32
|
+
}.reverse.first(4)
|
33
|
+
else
|
34
|
+
[]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# We may not have DYM, and DYM might not let us register error handlers
|
40
|
+
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
41
|
+
DidYouMean.correct_error(self, Correction)
|
42
|
+
end
|
18
43
|
end
|
19
44
|
|
20
45
|
class UnpermittedParameters < IndexError
|
@@ -26,26 +51,98 @@ module RubyPitaya
|
|
26
51
|
end
|
27
52
|
end
|
28
53
|
|
29
|
-
class
|
30
|
-
|
31
|
-
|
54
|
+
class UnfilteredParameters < ArgumentError
|
55
|
+
def initialize # :nodoc:
|
56
|
+
super("unable to convert unpermitted parameters to hash")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class Parameters
|
61
|
+
cattr_accessor :permit_all_parameters, instance_accessor: false, default: false
|
62
|
+
cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
|
63
|
+
|
64
|
+
delegate :keys, :key?, :has_key?, :member?, :values, :has_value?, :value?, :empty?, :include?,
|
65
|
+
:as_json, :to_s, :each_key, to: :@parameters
|
66
|
+
|
67
|
+
cattr_accessor :always_permitted_parameters, default: %w( controller action )
|
68
|
+
|
69
|
+
class << self
|
70
|
+
def nested_attribute?(key, value) # :nodoc:
|
71
|
+
/\A-?\d+\z/.match?(key) && (value.is_a?(Hash) || value.is_a?(Parameters))
|
72
|
+
end
|
73
|
+
end
|
32
74
|
|
33
|
-
|
75
|
+
def initialize(parameters = {})
|
76
|
+
@parameters = parameters.with_indifferent_access
|
77
|
+
@permitted = self.class.permit_all_parameters
|
78
|
+
end
|
34
79
|
|
35
|
-
|
36
|
-
|
37
|
-
|
80
|
+
def ==(other)
|
81
|
+
if other.respond_to?(:permitted?)
|
82
|
+
permitted? == other.permitted? && parameters == other.parameters
|
83
|
+
else
|
84
|
+
@parameters == other
|
85
|
+
end
|
86
|
+
end
|
87
|
+
alias eql? ==
|
38
88
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
89
|
+
def hash
|
90
|
+
[@parameters.hash, @permitted].hash
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_h
|
94
|
+
if permitted?
|
95
|
+
convert_parameters_to_hashes(@parameters, :to_h)
|
96
|
+
else
|
97
|
+
raise UnfilteredParameters
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_hash
|
102
|
+
to_h.to_hash
|
103
|
+
end
|
104
|
+
|
105
|
+
def to_query(*args)
|
106
|
+
to_h.to_query(*args)
|
107
|
+
end
|
108
|
+
alias_method :to_param, :to_query
|
109
|
+
|
110
|
+
def to_unsafe_h
|
111
|
+
convert_parameters_to_hashes(@parameters, :to_unsafe_h)
|
112
|
+
end
|
113
|
+
alias_method :to_unsafe_hash, :to_unsafe_h
|
114
|
+
|
115
|
+
def each_pair(&block)
|
116
|
+
return to_enum(__callee__) unless block_given?
|
117
|
+
@parameters.each_pair do |key, value|
|
118
|
+
yield [key, convert_hashes_to_parameters(key, value)]
|
119
|
+
end
|
120
|
+
|
121
|
+
self
|
122
|
+
end
|
123
|
+
alias_method :each, :each_pair
|
124
|
+
|
125
|
+
def each_value(&block)
|
126
|
+
return to_enum(:each_value) unless block_given?
|
127
|
+
@parameters.each_pair do |key, value|
|
128
|
+
yield convert_hashes_to_parameters(key, value)
|
129
|
+
end
|
130
|
+
|
131
|
+
self
|
132
|
+
end
|
133
|
+
|
134
|
+
def converted_arrays
|
135
|
+
@converted_arrays ||= Set.new
|
136
|
+
end
|
137
|
+
|
138
|
+
def permitted?
|
139
|
+
@permitted
|
42
140
|
end
|
43
141
|
|
44
142
|
def permit!
|
45
143
|
each_pair do |key, value|
|
46
|
-
value
|
47
|
-
|
48
|
-
_.permit! if _.respond_to? :permit!
|
144
|
+
Array.wrap(value).flatten.each do |v|
|
145
|
+
v.permit! if v.respond_to? :permit!
|
49
146
|
end
|
50
147
|
end
|
51
148
|
|
@@ -54,7 +151,13 @@ module RubyPitaya
|
|
54
151
|
end
|
55
152
|
|
56
153
|
def require(key)
|
57
|
-
|
154
|
+
return key.map { |k| require(k) } if key.is_a?(Array)
|
155
|
+
value = self[key]
|
156
|
+
if value.present? || value == false
|
157
|
+
value
|
158
|
+
else
|
159
|
+
raise ParameterMissing.new(key, @parameters.keys)
|
160
|
+
end
|
58
161
|
end
|
59
162
|
|
60
163
|
alias :required :require
|
@@ -66,7 +169,7 @@ module RubyPitaya
|
|
66
169
|
case filter
|
67
170
|
when Symbol, String
|
68
171
|
permitted_scalar_filter(params, filter)
|
69
|
-
when Hash
|
172
|
+
when Hash
|
70
173
|
hash_filter(params, filter)
|
71
174
|
end
|
72
175
|
end
|
@@ -77,169 +180,377 @@ module RubyPitaya
|
|
77
180
|
end
|
78
181
|
|
79
182
|
def [](key)
|
80
|
-
convert_hashes_to_parameters(key,
|
183
|
+
convert_hashes_to_parameters(key, @parameters[key])
|
184
|
+
end
|
185
|
+
|
186
|
+
def []=(key, value)
|
187
|
+
@parameters[key] = value
|
81
188
|
end
|
82
189
|
|
83
190
|
def fetch(key, *args)
|
84
|
-
|
85
|
-
|
86
|
-
|
191
|
+
convert_value_to_parameters(
|
192
|
+
@parameters.fetch(key) {
|
193
|
+
if block_given?
|
194
|
+
yield
|
195
|
+
else
|
196
|
+
args.fetch(0) { raise ActionController::ParameterMissing.new(key, @parameters.keys) }
|
197
|
+
end
|
198
|
+
}
|
199
|
+
)
|
200
|
+
end
|
201
|
+
|
202
|
+
def dig(*keys)
|
203
|
+
convert_hashes_to_parameters(keys.first, @parameters[keys.first])
|
204
|
+
@parameters.dig(*keys)
|
205
|
+
end
|
206
|
+
|
207
|
+
def slice!(*keys)
|
208
|
+
@parameters.slice!(*keys)
|
209
|
+
self
|
210
|
+
end
|
211
|
+
|
212
|
+
def except(*keys)
|
213
|
+
new_instance_with_inherited_permitted_status(@parameters.except(*keys))
|
214
|
+
end
|
215
|
+
|
216
|
+
def extract!(*keys)
|
217
|
+
new_instance_with_inherited_permitted_status(@parameters.extract!(*keys))
|
218
|
+
end
|
219
|
+
|
220
|
+
def transform_values
|
221
|
+
return to_enum(:transform_values) unless block_given?
|
222
|
+
new_instance_with_inherited_permitted_status(
|
223
|
+
@parameters.transform_values { |v| yield convert_value_to_parameters(v) }
|
224
|
+
)
|
225
|
+
end
|
226
|
+
|
227
|
+
def transform_values!
|
228
|
+
return to_enum(:transform_values!) unless block_given?
|
229
|
+
@parameters.transform_values! { |v| yield convert_value_to_parameters(v) }
|
230
|
+
self
|
231
|
+
end
|
232
|
+
|
233
|
+
def transform_keys(&block)
|
234
|
+
return to_enum(:transform_keys) unless block_given?
|
235
|
+
new_instance_with_inherited_permitted_status(
|
236
|
+
@parameters.transform_keys(&block)
|
237
|
+
)
|
238
|
+
end
|
239
|
+
|
240
|
+
def transform_keys!(&block)
|
241
|
+
return to_enum(:transform_keys!) unless block_given?
|
242
|
+
@parameters.transform_keys!(&block)
|
243
|
+
self
|
244
|
+
end
|
245
|
+
|
246
|
+
def deep_transform_keys(&block)
|
247
|
+
new_instance_with_inherited_permitted_status(
|
248
|
+
@parameters.deep_transform_keys(&block)
|
249
|
+
)
|
250
|
+
end
|
251
|
+
|
252
|
+
def deep_transform_keys!(&block)
|
253
|
+
@parameters.deep_transform_keys!(&block)
|
254
|
+
self
|
255
|
+
end
|
256
|
+
|
257
|
+
def delete(key, &block)
|
258
|
+
convert_value_to_parameters(@parameters.delete(key, &block))
|
259
|
+
end
|
260
|
+
|
261
|
+
def select(&block)
|
262
|
+
new_instance_with_inherited_permitted_status(@parameters.select(&block))
|
87
263
|
end
|
88
264
|
|
89
|
-
def
|
90
|
-
|
91
|
-
|
265
|
+
def select!(&block)
|
266
|
+
@parameters.select!(&block)
|
267
|
+
self
|
268
|
+
end
|
269
|
+
alias_method :keep_if, :select!
|
270
|
+
|
271
|
+
def reject(&block)
|
272
|
+
new_instance_with_inherited_permitted_status(@parameters.reject(&block))
|
273
|
+
end
|
274
|
+
|
275
|
+
def reject!(&block)
|
276
|
+
@parameters.reject!(&block)
|
277
|
+
self
|
278
|
+
end
|
279
|
+
alias_method :delete_if, :reject!
|
280
|
+
|
281
|
+
def compact
|
282
|
+
new_instance_with_inherited_permitted_status(@parameters.compact)
|
283
|
+
end
|
284
|
+
|
285
|
+
def compact!
|
286
|
+
self if @parameters.compact!
|
287
|
+
end
|
288
|
+
|
289
|
+
def compact_blank
|
290
|
+
reject { |_k, v| v.blank? }
|
291
|
+
end
|
292
|
+
|
293
|
+
def compact_blank!
|
294
|
+
reject! { |_k, v| v.blank? }
|
295
|
+
end
|
296
|
+
|
297
|
+
def values_at(*keys)
|
298
|
+
convert_value_to_parameters(@parameters.values_at(*keys))
|
299
|
+
end
|
300
|
+
|
301
|
+
def merge(other_hash)
|
302
|
+
new_instance_with_inherited_permitted_status(
|
303
|
+
@parameters.merge(other_hash.to_h)
|
304
|
+
)
|
305
|
+
end
|
306
|
+
|
307
|
+
def merge!(other_hash)
|
308
|
+
@parameters.merge!(other_hash.to_h)
|
309
|
+
self
|
310
|
+
end
|
311
|
+
|
312
|
+
def reverse_merge(other_hash)
|
313
|
+
new_instance_with_inherited_permitted_status(
|
314
|
+
other_hash.to_h.merge(@parameters)
|
315
|
+
)
|
316
|
+
end
|
317
|
+
alias_method :with_defaults, :reverse_merge
|
318
|
+
|
319
|
+
def reverse_merge!(other_hash)
|
320
|
+
@parameters.merge!(other_hash.to_h) { |key, left, right| left }
|
321
|
+
self
|
322
|
+
end
|
323
|
+
alias_method :with_defaults!, :reverse_merge!
|
324
|
+
|
325
|
+
def stringify_keys
|
326
|
+
dup
|
327
|
+
end
|
328
|
+
|
329
|
+
def inspect
|
330
|
+
"#<#{self.class} #{@parameters} permitted: #{@permitted}>"
|
331
|
+
end
|
332
|
+
|
333
|
+
def self.hook_into_yaml_loading
|
334
|
+
YAML.load_tags["!ruby/hash-with-ivars:ActionController::Parameters"] = name
|
335
|
+
YAML.load_tags["!ruby/hash:ActionController::Parameters"] = name
|
336
|
+
end
|
337
|
+
hook_into_yaml_loading
|
338
|
+
|
339
|
+
def init_with(coder)
|
340
|
+
case coder.tag
|
341
|
+
when "!ruby/hash:ActionController::Parameters"
|
342
|
+
@parameters = coder.map.with_indifferent_access
|
343
|
+
@permitted = false
|
344
|
+
when "!ruby/hash-with-ivars:ActionController::Parameters"
|
345
|
+
@parameters = coder.map["elements"].with_indifferent_access
|
346
|
+
@permitted = coder.map["ivars"][:@permitted]
|
347
|
+
when "!ruby/object:ActionController::Parameters"
|
348
|
+
@parameters, @permitted = coder.map["parameters"], coder.map["permitted"]
|
92
349
|
end
|
93
350
|
end
|
94
351
|
|
95
|
-
def
|
96
|
-
self.class.new(
|
97
|
-
duplicate.
|
98
|
-
duplicate.instance_variable_set :@permitted, @permitted
|
352
|
+
def deep_dup
|
353
|
+
self.class.new(@parameters.deep_dup).tap do |duplicate|
|
354
|
+
duplicate.permitted = @permitted
|
99
355
|
end
|
100
356
|
end
|
101
357
|
|
102
358
|
protected
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
359
|
+
|
360
|
+
attr_reader :parameters
|
361
|
+
|
362
|
+
attr_writer :permitted
|
363
|
+
|
364
|
+
def nested_attributes?
|
365
|
+
@parameters.any? { |k, v| Parameters.nested_attribute?(k, v) }
|
366
|
+
end
|
367
|
+
|
368
|
+
def each_nested_attribute
|
369
|
+
hash = self.class.new
|
370
|
+
self.each { |k, v| hash[k] = yield v if Parameters.nested_attribute?(k, v) }
|
371
|
+
hash
|
372
|
+
end
|
112
373
|
|
113
374
|
private
|
114
375
|
|
115
|
-
|
116
|
-
|
117
|
-
|
376
|
+
def new_instance_with_inherited_permitted_status(hash)
|
377
|
+
self.class.new(hash).tap do |new_instance|
|
378
|
+
new_instance.permitted = @permitted
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def convert_parameters_to_hashes(value, using)
|
383
|
+
case value
|
384
|
+
when Array
|
385
|
+
value.map { |v| convert_parameters_to_hashes(v, using) }
|
386
|
+
when Hash
|
387
|
+
value.transform_values do |v|
|
388
|
+
convert_parameters_to_hashes(v, using)
|
389
|
+
end.with_indifferent_access
|
390
|
+
when Parameters
|
391
|
+
value.send(using)
|
392
|
+
else
|
393
|
+
value
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
def convert_hashes_to_parameters(key, value)
|
398
|
+
converted = convert_value_to_parameters(value)
|
399
|
+
@parameters[key] = converted unless converted.equal?(value)
|
400
|
+
converted
|
401
|
+
end
|
402
|
+
|
403
|
+
def convert_value_to_parameters(value)
|
404
|
+
case value
|
405
|
+
when Array
|
406
|
+
return value if converted_arrays.member?(value)
|
407
|
+
converted = value.map { |_| convert_value_to_parameters(_) }
|
408
|
+
converted_arrays << converted
|
118
409
|
converted
|
410
|
+
when Hash
|
411
|
+
self.class.new(value)
|
412
|
+
else
|
413
|
+
value
|
119
414
|
end
|
415
|
+
end
|
120
416
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
417
|
+
def each_element(object, &block)
|
418
|
+
case object
|
419
|
+
when Array
|
420
|
+
object.grep(Parameters).map { |el| yield el }.compact
|
421
|
+
when Parameters
|
422
|
+
if object.nested_attributes?
|
423
|
+
object.each_nested_attribute(&block)
|
126
424
|
else
|
127
|
-
|
425
|
+
yield object
|
128
426
|
end
|
129
427
|
end
|
428
|
+
end
|
130
429
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
#
|
141
|
-
# If you modify this collection please update the README.
|
142
|
-
PERMITTED_SCALAR_TYPES = [
|
143
|
-
String,
|
144
|
-
Symbol,
|
145
|
-
NilClass,
|
146
|
-
Numeric,
|
147
|
-
TrueClass,
|
148
|
-
FalseClass,
|
149
|
-
Date,
|
150
|
-
Time,
|
151
|
-
# DateTimes are Dates, we document the type but avoid the redundant check.
|
152
|
-
StringIO,
|
153
|
-
IO,
|
154
|
-
]
|
155
|
-
|
156
|
-
def permitted_scalar?(value)
|
157
|
-
PERMITTED_SCALAR_TYPES.any? {|type| value.is_a?(type)}
|
158
|
-
end
|
159
|
-
|
160
|
-
def array_of_permitted_scalars?(value)
|
161
|
-
if value.is_a?(Array)
|
162
|
-
value.all? {|element| permitted_scalar?(element)}
|
430
|
+
def unpermitted_parameters!(params)
|
431
|
+
unpermitted_keys = unpermitted_keys(params)
|
432
|
+
if unpermitted_keys.any?
|
433
|
+
case self.class.action_on_unpermitted_parameters
|
434
|
+
when :log
|
435
|
+
name = "unpermitted_parameters.action_controller"
|
436
|
+
ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys)
|
437
|
+
when :raise
|
438
|
+
raise ActionController::UnpermittedParameters.new(unpermitted_keys)
|
163
439
|
end
|
164
440
|
end
|
441
|
+
end
|
165
442
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
end
|
443
|
+
def unpermitted_keys(params)
|
444
|
+
keys - params.keys - always_permitted_parameters
|
445
|
+
end
|
170
446
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
447
|
+
PERMITTED_SCALAR_TYPES = [
|
448
|
+
String,
|
449
|
+
Symbol,
|
450
|
+
NilClass,
|
451
|
+
Numeric,
|
452
|
+
TrueClass,
|
453
|
+
FalseClass,
|
454
|
+
Date,
|
455
|
+
Time,
|
456
|
+
# DateTimes are Dates, we document the type but avoid the redundant check.
|
457
|
+
StringIO,
|
458
|
+
IO,
|
459
|
+
]
|
460
|
+
|
461
|
+
def permitted_scalar?(value)
|
462
|
+
PERMITTED_SCALAR_TYPES.any? { |type| value.is_a?(type) }
|
463
|
+
end
|
464
|
+
|
465
|
+
def permitted_scalar_filter(params, permitted_key)
|
466
|
+
permitted_key = permitted_key.to_s
|
467
|
+
|
468
|
+
if has_key?(permitted_key) && permitted_scalar?(self[permitted_key])
|
469
|
+
params[permitted_key] = self[permitted_key]
|
176
470
|
end
|
177
471
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
472
|
+
each_key do |key|
|
473
|
+
next unless key =~ /\(\d+[if]?\)\z/
|
474
|
+
next unless $~.pre_match == permitted_key
|
475
|
+
|
476
|
+
params[key] = self[key] if permitted_scalar?(self[key])
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
def array_of_permitted_scalars?(value)
|
481
|
+
if value.is_a?(Array) && value.all? { |element| permitted_scalar?(element) }
|
482
|
+
yield value
|
182
483
|
end
|
484
|
+
end
|
183
485
|
|
184
|
-
|
185
|
-
|
486
|
+
def non_scalar?(value)
|
487
|
+
value.is_a?(Array) || value.is_a?(Parameters)
|
488
|
+
end
|
186
489
|
|
187
|
-
|
188
|
-
|
189
|
-
|
490
|
+
EMPTY_ARRAY = []
|
491
|
+
EMPTY_HASH = {}
|
492
|
+
def hash_filter(params, filter)
|
493
|
+
filter = filter.with_indifferent_access
|
190
494
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
495
|
+
# Slicing filters out non-declared keys.
|
496
|
+
slice(*filter.keys).each do |key, value|
|
497
|
+
next unless value
|
498
|
+
next unless has_key? key
|
499
|
+
|
500
|
+
if filter[key] == EMPTY_ARRAY
|
501
|
+
# Declaration { comment_ids: [] }.
|
502
|
+
array_of_permitted_scalars?(self[key]) do |val|
|
503
|
+
params[key] = val
|
504
|
+
end
|
505
|
+
elsif filter[key] == EMPTY_HASH
|
506
|
+
# Declaration { preferences: {} }.
|
507
|
+
if value.is_a?(Parameters)
|
508
|
+
params[key] = permit_any_in_parameters(value)
|
509
|
+
end
|
510
|
+
elsif non_scalar?(value)
|
511
|
+
# Declaration { user: :name } or { user: [:name, :age, { address: ... }] }.
|
512
|
+
params[key] = each_element(value) do |element|
|
513
|
+
element.permit(*Array.wrap(filter[key]))
|
204
514
|
end
|
205
515
|
end
|
206
516
|
end
|
517
|
+
end
|
207
518
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
519
|
+
def permit_any_in_parameters(params)
|
520
|
+
self.class.new.tap do |sanitized|
|
521
|
+
params.each do |key, value|
|
522
|
+
case value
|
523
|
+
when ->(v) { permitted_scalar?(v) }
|
524
|
+
sanitized[key] = value
|
525
|
+
when Array
|
526
|
+
sanitized[key] = permit_any_in_array(value)
|
527
|
+
when Parameters
|
528
|
+
sanitized[key] = permit_any_in_parameters(value)
|
529
|
+
else
|
530
|
+
# Filter this one out.
|
531
|
+
end
|
218
532
|
end
|
219
533
|
end
|
534
|
+
end
|
220
535
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
case self.class.action_on_unpermitted_parameters
|
232
|
-
when :log
|
233
|
-
name = "unpermitted_parameters.action_controller"
|
234
|
-
ActiveSupport::Notifications.instrument(name, :keys => unpermitted_keys)
|
235
|
-
when :raise
|
236
|
-
raise UnpermittedParameters.new(unpermitted_keys)
|
536
|
+
def permit_any_in_array(array)
|
537
|
+
[].tap do |sanitized|
|
538
|
+
array.each do |element|
|
539
|
+
case element
|
540
|
+
when ->(e) { permitted_scalar?(e) }
|
541
|
+
sanitized << element
|
542
|
+
when Parameters
|
543
|
+
sanitized << permit_any_in_parameters(element)
|
544
|
+
else
|
545
|
+
# Filter this one out.
|
237
546
|
end
|
238
547
|
end
|
239
548
|
end
|
549
|
+
end
|
240
550
|
|
241
|
-
|
242
|
-
|
243
|
-
|
551
|
+
def initialize_copy(source)
|
552
|
+
super
|
553
|
+
@parameters = @parameters.dup
|
554
|
+
end
|
244
555
|
end
|
245
556
|
end
|