durable_parameters 0.2.3
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +853 -0
- data/Rakefile +29 -0
- data/app/params/account_params.rb.example +38 -0
- data/app/params/application_params.rb +16 -0
- data/lib/durable_parameters/adapters/hanami.rb +138 -0
- data/lib/durable_parameters/adapters/rage.rb +124 -0
- data/lib/durable_parameters/adapters/rails.rb +280 -0
- data/lib/durable_parameters/adapters/sinatra.rb +91 -0
- data/lib/durable_parameters/core/application_params.rb +334 -0
- data/lib/durable_parameters/core/configuration.rb +83 -0
- data/lib/durable_parameters/core/forbidden_attributes_protection.rb +48 -0
- data/lib/durable_parameters/core/parameters.rb +643 -0
- data/lib/durable_parameters/core/params_registry.rb +110 -0
- data/lib/durable_parameters/core.rb +15 -0
- data/lib/durable_parameters/log_subscriber.rb +34 -0
- data/lib/durable_parameters/railtie.rb +65 -0
- data/lib/durable_parameters/version.rb +7 -0
- data/lib/durable_parameters.rb +41 -0
- data/lib/generators/rails/USAGE +12 -0
- data/lib/generators/rails/durable_parameters_controller_generator.rb +17 -0
- data/lib/generators/rails/templates/controller.rb +94 -0
- data/lib/legacy/action_controller/application_params.rb +235 -0
- data/lib/legacy/action_controller/parameters.rb +524 -0
- data/lib/legacy/action_controller/params_registry.rb +108 -0
- data/lib/legacy/active_model/forbidden_attributes_protection.rb +40 -0
- data/test/action_controller_required_params_test.rb +36 -0
- data/test/action_controller_tainted_params_test.rb +29 -0
- data/test/active_model_mass_assignment_taint_protection_test.rb +25 -0
- data/test/application_params_array_test.rb +245 -0
- data/test/application_params_edge_cases_test.rb +361 -0
- data/test/application_params_test.rb +893 -0
- data/test/controller_generator_test.rb +31 -0
- data/test/core_parameters_test.rb +2376 -0
- data/test/durable_parameters_test.rb +115 -0
- data/test/enhanced_error_messages_test.rb +120 -0
- data/test/gemfiles/Gemfile.rails-3.0.x +14 -0
- data/test/gemfiles/Gemfile.rails-3.1.x +14 -0
- data/test/gemfiles/Gemfile.rails-3.2.x +14 -0
- data/test/log_on_unpermitted_params_test.rb +49 -0
- data/test/metadata_validation_test.rb +294 -0
- data/test/multi_parameter_attributes_test.rb +38 -0
- data/test/parameters_core_methods_test.rb +503 -0
- data/test/parameters_integration_test.rb +553 -0
- data/test/parameters_permit_test.rb +491 -0
- data/test/parameters_require_test.rb +9 -0
- data/test/parameters_taint_test.rb +98 -0
- data/test/params_registry_concurrency_test.rb +422 -0
- data/test/params_registry_test.rb +112 -0
- data/test/permit_by_model_test.rb +227 -0
- data/test/raise_on_unpermitted_params_test.rb +32 -0
- data/test/test_helper.rb +38 -0
- data/test/transform_params_edge_cases_test.rb +526 -0
- data/test/transformation_test.rb +360 -0
- metadata +223 -0
|
@@ -0,0 +1,2376 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
|
|
5
|
+
class CoreParametersTest < Minitest::Test
|
|
6
|
+
def setup
|
|
7
|
+
# Ensure no action on unpermitted parameters for testing
|
|
8
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = nil
|
|
9
|
+
|
|
10
|
+
@params = StrongParameters::Core::Parameters.new(
|
|
11
|
+
name: 'John',
|
|
12
|
+
email: 'john@example.com',
|
|
13
|
+
age: 30,
|
|
14
|
+
admin: true,
|
|
15
|
+
profile: {
|
|
16
|
+
bio: 'Developer',
|
|
17
|
+
location: 'NYC'
|
|
18
|
+
},
|
|
19
|
+
tags: ['ruby', 'rails'],
|
|
20
|
+
scores: [95, 87, 92]
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Test initialization
|
|
25
|
+
def test_initialization_with_nil
|
|
26
|
+
params = StrongParameters::Core::Parameters.new(nil)
|
|
27
|
+
assert_equal({}, params.to_h)
|
|
28
|
+
assert !params.permitted?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_initialization_with_empty_hash
|
|
32
|
+
params = StrongParameters::Core::Parameters.new({})
|
|
33
|
+
assert_equal({}, params.to_h)
|
|
34
|
+
assert !params.permitted?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_initialization_with_hash
|
|
38
|
+
params = StrongParameters::Core::Parameters.new(key: 'value')
|
|
39
|
+
assert_equal 'value', params[:key]
|
|
40
|
+
assert !params.permitted?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_initialization_normalizes_keys
|
|
44
|
+
params = StrongParameters::Core::Parameters.new('name' => 'John', :email => 'test@example.com')
|
|
45
|
+
assert_equal 'John', params[:name]
|
|
46
|
+
assert_equal 'test@example.com', params[:email]
|
|
47
|
+
assert_equal ['name', 'email'], params.keys
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def test_initialization_with_nested_hashes
|
|
51
|
+
params = StrongParameters::Core::Parameters.new(
|
|
52
|
+
user: { profile: { name: 'John' } }
|
|
53
|
+
)
|
|
54
|
+
assert params[:user].is_a?(StrongParameters::Core::Parameters)
|
|
55
|
+
assert params[:user][:profile].is_a?(StrongParameters::Core::Parameters)
|
|
56
|
+
assert_equal 'John', params[:user][:profile][:name]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def test_initialization_with_arrays_of_hashes
|
|
60
|
+
params = StrongParameters::Core::Parameters.new(
|
|
61
|
+
users: [{ name: 'John' }, { name: 'Jane' }]
|
|
62
|
+
)
|
|
63
|
+
assert params[:users].is_a?(Array)
|
|
64
|
+
assert params[:users][0].is_a?(StrongParameters::Core::Parameters)
|
|
65
|
+
assert params[:users][1].is_a?(StrongParameters::Core::Parameters)
|
|
66
|
+
assert_equal 'John', params[:users][0][:name]
|
|
67
|
+
assert_equal 'Jane', params[:users][1][:name]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_initialization_with_deeply_nested_structure
|
|
71
|
+
params = StrongParameters::Core::Parameters.new(
|
|
72
|
+
user: {
|
|
73
|
+
profile: {
|
|
74
|
+
settings: {
|
|
75
|
+
notifications: {
|
|
76
|
+
email: true,
|
|
77
|
+
sms: false
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
assert params[:user].is_a?(StrongParameters::Core::Parameters)
|
|
85
|
+
assert params[:user][:profile].is_a?(StrongParameters::Core::Parameters)
|
|
86
|
+
assert params[:user][:profile][:settings].is_a?(StrongParameters::Core::Parameters)
|
|
87
|
+
assert params[:user][:profile][:settings][:notifications].is_a?(StrongParameters::Core::Parameters)
|
|
88
|
+
assert_equal true, params[:user][:profile][:settings][:notifications][:email]
|
|
89
|
+
assert_equal false, params[:user][:profile][:settings][:notifications][:sms]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def test_initialization_with_large_hash
|
|
93
|
+
large_hash = {}
|
|
94
|
+
1000.times { |i| large_hash["key#{i}"] = "value#{i}" }
|
|
95
|
+
|
|
96
|
+
params = StrongParameters::Core::Parameters.new(large_hash)
|
|
97
|
+
assert_equal 1000, params.size
|
|
98
|
+
assert_equal 'value0', params[:key0]
|
|
99
|
+
assert_equal 'value999', params[:key999]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def test_initialization_with_mixed_key_types
|
|
103
|
+
params = StrongParameters::Core::Parameters.new(
|
|
104
|
+
'string_key' => 'string_value',
|
|
105
|
+
:symbol_key => 'symbol_value',
|
|
106
|
+
123 => 'numeric_key_value'
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
assert_equal 'string_value', params['string_key']
|
|
110
|
+
assert_equal 'symbol_value', params[:symbol_key]
|
|
111
|
+
assert_equal 'numeric_key_value', params['123']
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def test_initialization_with_frozen_hash
|
|
115
|
+
frozen_hash = { name: 'John', age: 30 }.freeze
|
|
116
|
+
params = StrongParameters::Core::Parameters.new(frozen_hash)
|
|
117
|
+
|
|
118
|
+
assert_equal 'John', params[:name]
|
|
119
|
+
assert_equal 30, params[:age]
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def test_initialization_with_empty_nested_hashes
|
|
123
|
+
params = StrongParameters::Core::Parameters.new(
|
|
124
|
+
user: {},
|
|
125
|
+
profile: { settings: {} }
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
assert params[:user].is_a?(StrongParameters::Core::Parameters)
|
|
129
|
+
assert params[:user].empty?
|
|
130
|
+
assert params[:profile][:settings].is_a?(StrongParameters::Core::Parameters)
|
|
131
|
+
assert params[:profile][:settings].empty?
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Test permitted flag
|
|
135
|
+
def test_permitted_starts_false
|
|
136
|
+
assert !@params.permitted?
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def test_permit_bang_sets_permitted_true
|
|
140
|
+
@params.permit!
|
|
141
|
+
assert @params.permitted?
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def test_permit_bang_returns_self
|
|
145
|
+
result = @params.permit!
|
|
146
|
+
assert_equal @params.object_id, result.object_id
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def test_permit_bang_on_nested_parameters
|
|
150
|
+
@params.permit!
|
|
151
|
+
assert @params[:profile].permitted?
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def test_permit_bang_on_array_of_parameters
|
|
155
|
+
params = StrongParameters::Core::Parameters.new(
|
|
156
|
+
users: [{ name: 'John' }, { name: 'Jane' }]
|
|
157
|
+
)
|
|
158
|
+
params.permit!
|
|
159
|
+
assert params[:users][0].permitted?
|
|
160
|
+
assert params[:users][1].permitted?
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Test require method
|
|
164
|
+
def test_require_returns_value_when_present
|
|
165
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
166
|
+
result = params.require(:user)
|
|
167
|
+
assert_equal 'John', result[:name]
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def test_require_raises_when_key_missing
|
|
171
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
172
|
+
@params.require(:nonexistent)
|
|
173
|
+
end
|
|
174
|
+
assert_equal 'nonexistent', error.param
|
|
175
|
+
assert_match(/param is missing or the value is empty: nonexistent/, error.message)
|
|
176
|
+
assert_match(/Available keys: name, email, age, admin, profile, tags, scores/, error.message)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def test_require_raises_with_suggestions
|
|
180
|
+
params = StrongParameters::Core::Parameters.new(usr: { name: 'John' }, usrname: 'test')
|
|
181
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
182
|
+
params.require(:user)
|
|
183
|
+
end
|
|
184
|
+
assert_match(/Did you mean\? usr, usrname/, error.message)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def test_parameter_missing_with_no_similar_keys
|
|
188
|
+
params = StrongParameters::Core::Parameters.new(xyz: 'value', abc: 'other')
|
|
189
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
190
|
+
params.require(:user)
|
|
191
|
+
end
|
|
192
|
+
assert_match(/param is missing or the value is empty: user/, error.message)
|
|
193
|
+
assert_match(/Available keys: xyz, abc/, error.message)
|
|
194
|
+
refute_match(/Did you mean\?/, error.message)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def test_parameter_missing_with_many_similar_keys
|
|
198
|
+
params = StrongParameters::Core::Parameters.new(
|
|
199
|
+
usr: 'value',
|
|
200
|
+
user_name: 'value',
|
|
201
|
+
user_email: 'value',
|
|
202
|
+
username: 'value',
|
|
203
|
+
usr_profile: 'value'
|
|
204
|
+
)
|
|
205
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
206
|
+
params.require(:user)
|
|
207
|
+
end
|
|
208
|
+
# Should limit to 3 suggestions
|
|
209
|
+
assert_match(/Did you mean\? usr, user_name, user_email/, error.message)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def test_require_raises_when_value_empty
|
|
213
|
+
params = StrongParameters::Core::Parameters.new(user: nil)
|
|
214
|
+
assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
215
|
+
params.require(:user)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def test_require_raises_when_value_empty_string
|
|
220
|
+
params = StrongParameters::Core::Parameters.new(user: '')
|
|
221
|
+
assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
222
|
+
params.require(:user)
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def test_require_raises_when_value_empty_array
|
|
227
|
+
params = StrongParameters::Core::Parameters.new(user: [])
|
|
228
|
+
assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
229
|
+
params.require(:user)
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def test_require_returns_false_when_present
|
|
234
|
+
params = StrongParameters::Core::Parameters.new(active: false)
|
|
235
|
+
assert_equal false, params.require(:active)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def test_require_returns_zero_when_present
|
|
239
|
+
params = StrongParameters::Core::Parameters.new(count: 0)
|
|
240
|
+
assert_equal 0, params.require(:count)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def test_require_raises_when_value_empty_hash
|
|
244
|
+
params = StrongParameters::Core::Parameters.new(user: {})
|
|
245
|
+
assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
246
|
+
params.require(:user)
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def test_require_accepts_string_key
|
|
251
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
252
|
+
result = params.require('user')
|
|
253
|
+
assert_equal 'John', result[:name]
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def test_require_sets_required_key_on_result
|
|
257
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
258
|
+
result = params.require(:user)
|
|
259
|
+
assert_equal :user, result.required_key
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def test_required_alias_works
|
|
263
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
264
|
+
result = params.required(:user)
|
|
265
|
+
assert_equal 'John', result[:name]
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def test_require_with_numeric_key
|
|
269
|
+
params = StrongParameters::Core::Parameters.new('123' => { name: 'John' })
|
|
270
|
+
result = params.require(123)
|
|
271
|
+
assert_equal 'John', result[:name]
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def test_require_with_false_value
|
|
275
|
+
params = StrongParameters::Core::Parameters.new(active: false)
|
|
276
|
+
result = params.require(:active)
|
|
277
|
+
assert_equal false, result
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def test_require_with_zero_value
|
|
281
|
+
params = StrongParameters::Core::Parameters.new(count: 0)
|
|
282
|
+
result = params.require(:count)
|
|
283
|
+
assert_equal 0, result
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
def test_require_with_nested_require
|
|
287
|
+
params = StrongParameters::Core::Parameters.new(
|
|
288
|
+
company: {
|
|
289
|
+
employees: [
|
|
290
|
+
{ name: 'Alice' },
|
|
291
|
+
{ name: 'Bob' }
|
|
292
|
+
]
|
|
293
|
+
}
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
company = params.require(:company)
|
|
297
|
+
employees = company.require(:employees)
|
|
298
|
+
assert employees.is_a?(Array)
|
|
299
|
+
assert_equal 'Alice', employees[0][:name]
|
|
300
|
+
assert_equal 'Bob', employees[1][:name]
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def test_require_preserves_required_key_through_multiple_calls
|
|
304
|
+
params = StrongParameters::Core::Parameters.new(
|
|
305
|
+
organization: {
|
|
306
|
+
department: {
|
|
307
|
+
team: { name: 'Dev Team' }
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
org = params.require(:organization)
|
|
313
|
+
dept = org.require(:department)
|
|
314
|
+
team = dept.require(:team)
|
|
315
|
+
|
|
316
|
+
assert_equal :organization, org.required_key
|
|
317
|
+
assert_equal :organization, dept.required_key # Inherits from parent
|
|
318
|
+
assert_equal :organization, team.required_key
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def test_require_with_array_value
|
|
322
|
+
params = StrongParameters::Core::Parameters.new(tags: ['ruby', 'rails'])
|
|
323
|
+
result = params.require(:tags)
|
|
324
|
+
assert_equal ['ruby', 'rails'], result
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def test_require_with_empty_array
|
|
328
|
+
params = StrongParameters::Core::Parameters.new(items: [])
|
|
329
|
+
assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
330
|
+
params.require(:items)
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# Test permit method
|
|
335
|
+
def test_permit_with_single_key
|
|
336
|
+
permitted = @params.permit(:name)
|
|
337
|
+
assert_equal 'John', permitted[:name]
|
|
338
|
+
assert_nil permitted[:email]
|
|
339
|
+
assert permitted.permitted?
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def test_permit_with_multiple_keys
|
|
343
|
+
permitted = @params.permit(:name, :email, :age)
|
|
344
|
+
assert_equal 'John', permitted[:name]
|
|
345
|
+
assert_equal 'john@example.com', permitted[:email]
|
|
346
|
+
assert_equal 30, permitted[:age]
|
|
347
|
+
assert_nil permitted[:admin]
|
|
348
|
+
assert permitted.permitted?
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def test_permit_with_string_keys
|
|
352
|
+
permitted = @params.permit('name', 'email')
|
|
353
|
+
assert_equal 'John', permitted[:name]
|
|
354
|
+
assert_equal 'john@example.com', permitted[:email]
|
|
355
|
+
assert permitted.permitted?
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def test_permit_returns_new_instance
|
|
359
|
+
permitted = @params.permit(:name)
|
|
360
|
+
refute_equal @params.object_id, permitted.object_id
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
def test_permit_doesnt_modify_original
|
|
364
|
+
permitted = @params.permit(:name)
|
|
365
|
+
assert !@params.permitted?
|
|
366
|
+
assert permitted.permitted?
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
def test_permit_with_nested_hash
|
|
370
|
+
permitted = @params.permit(profile: [:bio, :location])
|
|
371
|
+
assert_equal 'Developer', permitted[:profile][:bio]
|
|
372
|
+
assert_equal 'NYC', permitted[:profile][:location]
|
|
373
|
+
assert permitted[:profile].permitted?
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
def test_permit_with_array_of_scalars
|
|
377
|
+
permitted = @params.permit(tags: [])
|
|
378
|
+
assert_equal ['ruby', 'rails'], permitted[:tags]
|
|
379
|
+
assert permitted.permitted?
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def test_permit_with_array_of_scalars_explicit
|
|
383
|
+
permitted = @params.permit(scores: [])
|
|
384
|
+
assert_equal [95, 87, 92], permitted[:scores]
|
|
385
|
+
assert permitted.permitted?
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def test_permit_with_complex_nested_structure
|
|
389
|
+
params = StrongParameters::Core::Parameters.new(
|
|
390
|
+
user: {
|
|
391
|
+
name: 'John',
|
|
392
|
+
profile: {
|
|
393
|
+
bio: 'Developer',
|
|
394
|
+
skills: ['ruby', 'rails']
|
|
395
|
+
},
|
|
396
|
+
addresses: [
|
|
397
|
+
{ city: 'NYC', zip: '10001' },
|
|
398
|
+
{ city: 'LA', zip: '90210' }
|
|
399
|
+
]
|
|
400
|
+
}
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
permitted = params.permit(
|
|
404
|
+
user: [
|
|
405
|
+
:name,
|
|
406
|
+
profile: [:bio, skills: []],
|
|
407
|
+
addresses: [:city, :zip]
|
|
408
|
+
]
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
assert_equal 'John', permitted[:user][:name]
|
|
412
|
+
assert_equal 'Developer', permitted[:user][:profile][:bio]
|
|
413
|
+
assert_equal ['ruby', 'rails'], permitted[:user][:profile][:skills]
|
|
414
|
+
assert_equal 'NYC', permitted[:user][:addresses][0][:city]
|
|
415
|
+
assert_equal '10001', permitted[:user][:addresses][0][:zip]
|
|
416
|
+
assert_equal 'LA', permitted[:user][:addresses][1][:city]
|
|
417
|
+
assert_equal '90210', permitted[:user][:addresses][1][:zip]
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
def test_permit_with_extremely_nested_structure
|
|
421
|
+
params = StrongParameters::Core::Parameters.new(
|
|
422
|
+
organization: {
|
|
423
|
+
departments: [
|
|
424
|
+
{
|
|
425
|
+
name: 'Engineering',
|
|
426
|
+
teams: [
|
|
427
|
+
{
|
|
428
|
+
name: 'Backend',
|
|
429
|
+
members: [
|
|
430
|
+
{ name: 'Alice', role: 'senior' },
|
|
431
|
+
{ name: 'Bob', role: 'junior' }
|
|
432
|
+
]
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
name: 'Frontend',
|
|
436
|
+
members: [
|
|
437
|
+
{ name: 'Charlie', role: 'lead' }
|
|
438
|
+
]
|
|
439
|
+
}
|
|
440
|
+
]
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
name: 'Sales',
|
|
444
|
+
teams: []
|
|
445
|
+
}
|
|
446
|
+
]
|
|
447
|
+
}
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
permitted = params.permit(
|
|
451
|
+
organization: {
|
|
452
|
+
departments: [
|
|
453
|
+
:name,
|
|
454
|
+
teams: [
|
|
455
|
+
:name,
|
|
456
|
+
members: [:name, :role]
|
|
457
|
+
]
|
|
458
|
+
]
|
|
459
|
+
}
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
assert_equal 'Engineering', permitted[:organization][:departments][0][:name]
|
|
463
|
+
assert_equal 'Backend', permitted[:organization][:departments][0][:teams][0][:name]
|
|
464
|
+
assert_equal 'Alice', permitted[:organization][:departments][0][:teams][0][:members][0][:name]
|
|
465
|
+
assert_equal 'senior', permitted[:organization][:departments][0][:teams][0][:members][0][:role]
|
|
466
|
+
assert_equal 'Sales', permitted[:organization][:departments][1][:name]
|
|
467
|
+
assert_equal [], permitted[:organization][:departments][1][:teams]
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
def test_permit_with_mixed_array_and_hash_filters
|
|
471
|
+
params = StrongParameters::Core::Parameters.new(
|
|
472
|
+
posts: [
|
|
473
|
+
{ title: 'Post 1', tags: ['ruby', 'rails'], metadata: { published: true } },
|
|
474
|
+
{ title: 'Post 2', tags: ['js'], metadata: { published: false } }
|
|
475
|
+
],
|
|
476
|
+
categories: ['tech', 'news']
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
permitted = params.permit(
|
|
480
|
+
posts: [:title, tags: [], metadata: [:published]],
|
|
481
|
+
categories: []
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
assert_equal 'Post 1', permitted[:posts][0][:title]
|
|
485
|
+
assert_equal ['ruby', 'rails'], permitted[:posts][0][:tags]
|
|
486
|
+
assert_equal true, permitted[:posts][0][:metadata][:published]
|
|
487
|
+
assert_equal 'Post 2', permitted[:posts][1][:title]
|
|
488
|
+
assert_equal ['js'], permitted[:posts][1][:tags]
|
|
489
|
+
assert_equal false, permitted[:posts][1][:metadata][:published]
|
|
490
|
+
assert_equal ['tech', 'news'], permitted[:categories]
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
def test_permit_with_fields_for_style_arrays
|
|
494
|
+
params = StrongParameters::Core::Parameters.new(
|
|
495
|
+
'0' => { name: 'John', age: '30', secret: 'hidden' },
|
|
496
|
+
'1' => { name: 'Jane', age: '25', secret: 'also_hidden' },
|
|
497
|
+
'2' => { name: 'Bob', age: '35' }
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
permitted = params.permit(
|
|
501
|
+
'0' => [:name, :age],
|
|
502
|
+
'1' => [:name, :age],
|
|
503
|
+
'2' => [:name, :age]
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
assert_equal 'John', permitted['0'][:name]
|
|
507
|
+
assert_equal '30', permitted['0'][:age]
|
|
508
|
+
assert_nil permitted['0'][:secret]
|
|
509
|
+
assert_equal 'Jane', permitted['1'][:name]
|
|
510
|
+
assert_equal '25', permitted['1'][:age]
|
|
511
|
+
assert_nil permitted['1'][:secret]
|
|
512
|
+
assert_equal 'Bob', permitted['2'][:name]
|
|
513
|
+
assert_equal '35', permitted['2'][:age]
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
def test_permit_with_negative_indexed_fields_for
|
|
517
|
+
params = StrongParameters::Core::Parameters.new(
|
|
518
|
+
'-1' => { name: 'John' },
|
|
519
|
+
'0' => { name: 'Jane' }
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
permitted = params.permit(
|
|
523
|
+
'-1' => [:name],
|
|
524
|
+
'0' => [:name]
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
assert_equal 'John', permitted['-1'][:name]
|
|
528
|
+
assert_equal 'Jane', permitted['0'][:name]
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
def test_permit_with_nil_values
|
|
532
|
+
params = StrongParameters::Core::Parameters.new(name: 'John', age: nil, active: false)
|
|
533
|
+
permitted = params.permit(:name, :age, :active)
|
|
534
|
+
assert_equal 'John', permitted[:name]
|
|
535
|
+
assert_nil permitted[:age]
|
|
536
|
+
assert_equal false, permitted[:active]
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
def test_permit_with_empty_arrays
|
|
540
|
+
params = StrongParameters::Core::Parameters.new(tags: [], scores: [1, 2, 3])
|
|
541
|
+
permitted = params.permit(tags: [], scores: [])
|
|
542
|
+
assert_equal [], permitted[:tags]
|
|
543
|
+
assert_equal [1, 2, 3], permitted[:scores]
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
def test_permit_with_mixed_array_types
|
|
547
|
+
params = StrongParameters::Core::Parameters.new(items: ['string', 42, true, nil])
|
|
548
|
+
permitted = params.permit(items: [])
|
|
549
|
+
assert_equal ['string', 42, true, nil], permitted[:items]
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
def test_permit_with_invalid_array_elements
|
|
553
|
+
params = StrongParameters::Core::Parameters.new(items: ['valid', {}])
|
|
554
|
+
permitted = params.permit(items: [])
|
|
555
|
+
# Should not permit array with invalid elements
|
|
556
|
+
assert_nil permitted[:items]
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
def test_permit_with_deeply_nested_empty_hashes
|
|
560
|
+
params = StrongParameters::Core::Parameters.new(user: { profile: {} })
|
|
561
|
+
permitted = params.permit(user: { profile: {} })
|
|
562
|
+
assert_equal({}, permitted[:user][:profile].to_h)
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
def test_permit_with_duplicate_keys_in_filters
|
|
566
|
+
params = StrongParameters::Core::Parameters.new(name: 'John', age: 30)
|
|
567
|
+
permitted = params.permit(:name, :name, :age)
|
|
568
|
+
assert_equal 'John', permitted[:name]
|
|
569
|
+
assert_equal 30, permitted[:age]
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
def test_permit_with_mixed_filters_and_unpermitted_keys
|
|
573
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :raise
|
|
574
|
+
|
|
575
|
+
params = StrongParameters::Core::Parameters.new(
|
|
576
|
+
user: {
|
|
577
|
+
name: 'John',
|
|
578
|
+
email: 'john@example.com',
|
|
579
|
+
admin: true,
|
|
580
|
+
profile: {
|
|
581
|
+
bio: 'Developer',
|
|
582
|
+
secret: 'hidden'
|
|
583
|
+
}
|
|
584
|
+
},
|
|
585
|
+
extra: 'value'
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
assert_raises(StrongParameters::Core::UnpermittedParameters) do
|
|
589
|
+
params.permit(
|
|
590
|
+
user: [:name, :email, profile: [:bio]], # admin and secret not permitted
|
|
591
|
+
extra: [] # extra not permitted
|
|
592
|
+
)
|
|
593
|
+
end
|
|
594
|
+
end
|
|
595
|
+
|
|
596
|
+
def test_permit_with_fields_for_style_and_multi_param
|
|
597
|
+
params = StrongParameters::Core::Parameters.new(
|
|
598
|
+
'posts' => {
|
|
599
|
+
'0' => { title: 'First Post', content: 'Content 1' },
|
|
600
|
+
'1' => { title: 'Second Post', content: 'Content 2' }
|
|
601
|
+
},
|
|
602
|
+
'event_date(1i)' => '2023',
|
|
603
|
+
'event_date(2i)' => '12',
|
|
604
|
+
'event_date(3i)' => '25'
|
|
605
|
+
)
|
|
606
|
+
|
|
607
|
+
permitted = params.permit(
|
|
608
|
+
{posts: [:title, :content]},
|
|
609
|
+
:event_date
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
assert_equal 'First Post', permitted[:posts]['0'][:title]
|
|
613
|
+
assert_equal 'Content 2', permitted[:posts]['1'][:content]
|
|
614
|
+
assert_equal '2023', permitted['event_date(1i)']
|
|
615
|
+
assert_equal '12', permitted['event_date(2i)']
|
|
616
|
+
assert_equal '25', permitted['event_date(3i)']
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
# Test transform_params method
|
|
620
|
+
def test_transform_params_with_inference
|
|
621
|
+
# Mock the ParamsRegistry
|
|
622
|
+
StrongParameters::Core::ParamsRegistry.register(:user, Class.new(StrongParameters::Core::ApplicationParams) do
|
|
623
|
+
def self.permitted_attributes(action: nil)
|
|
624
|
+
[:name, :email]
|
|
625
|
+
end
|
|
626
|
+
end)
|
|
627
|
+
|
|
628
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'john@example.com', admin: true })
|
|
629
|
+
user_params = params.require(:user)
|
|
630
|
+
permitted = user_params.transform_params
|
|
631
|
+
|
|
632
|
+
assert_equal 'John', permitted[:name]
|
|
633
|
+
assert_equal 'john@example.com', permitted[:email]
|
|
634
|
+
assert_nil permitted[:admin]
|
|
635
|
+
assert permitted.permitted?
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
def test_transform_params_with_explicit_class
|
|
639
|
+
user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
640
|
+
def self.permitted_attributes(action: nil)
|
|
641
|
+
[:name, :age]
|
|
642
|
+
end
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John', age: 30, admin: true })
|
|
646
|
+
user_params = params.require(:user)
|
|
647
|
+
permitted = user_params.transform_params(user_params_class)
|
|
648
|
+
|
|
649
|
+
assert_equal 'John', permitted[:name]
|
|
650
|
+
assert_equal 30, permitted[:age]
|
|
651
|
+
assert_nil permitted[:admin]
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
def test_transform_params_with_action
|
|
655
|
+
user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
656
|
+
def self.permitted_attributes(action: nil)
|
|
657
|
+
case action
|
|
658
|
+
when :create
|
|
659
|
+
[:name, :email]
|
|
660
|
+
when :update
|
|
661
|
+
[:name, :age]
|
|
662
|
+
else
|
|
663
|
+
[]
|
|
664
|
+
end
|
|
665
|
+
end
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'john@example.com', age: 30 })
|
|
669
|
+
user_params = params.require(:user)
|
|
670
|
+
|
|
671
|
+
create_permitted = user_params.transform_params(user_params_class, action: :create)
|
|
672
|
+
assert_equal 'John', create_permitted[:name]
|
|
673
|
+
assert_equal 'john@example.com', create_permitted[:email]
|
|
674
|
+
assert_nil create_permitted[:age]
|
|
675
|
+
|
|
676
|
+
update_permitted = user_params.transform_params(user_params_class, action: :update)
|
|
677
|
+
assert_equal 'John', update_permitted[:name]
|
|
678
|
+
assert_equal 30, update_permitted[:age]
|
|
679
|
+
assert_nil update_permitted[:email]
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
def test_transform_params_with_additional_attrs
|
|
683
|
+
user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
684
|
+
def self.permitted_attributes(action: nil)
|
|
685
|
+
[:name]
|
|
686
|
+
end
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John', token: 'abc123', admin: true })
|
|
690
|
+
user_params = params.require(:user)
|
|
691
|
+
permitted = user_params.transform_params(user_params_class, additional_attrs: [:token])
|
|
692
|
+
|
|
693
|
+
assert_equal 'John', permitted[:name]
|
|
694
|
+
assert_equal 'abc123', permitted[:token]
|
|
695
|
+
assert_nil permitted[:admin]
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
def test_transform_params_with_metadata
|
|
699
|
+
user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
700
|
+
allow :name
|
|
701
|
+
allow :admin_override
|
|
702
|
+
metadata :current_user
|
|
703
|
+
|
|
704
|
+
def self.apply_transformations(params, options)
|
|
705
|
+
current_user = options[:current_user]
|
|
706
|
+
if current_user&.admin?
|
|
707
|
+
params.merge('admin_override' => true)
|
|
708
|
+
else
|
|
709
|
+
params
|
|
710
|
+
end
|
|
711
|
+
end
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
715
|
+
user_params = params.require(:user)
|
|
716
|
+
|
|
717
|
+
# Mock current_user
|
|
718
|
+
current_user = Object.new
|
|
719
|
+
def current_user.admin?; true; end
|
|
720
|
+
|
|
721
|
+
permitted = user_params.transform_params(user_params_class, current_user: current_user)
|
|
722
|
+
assert_equal 'John', permitted[:name]
|
|
723
|
+
assert_equal true, permitted[:admin_override]
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
def test_transform_params_with_invalid_metadata
|
|
727
|
+
user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
728
|
+
def self.metadata_allowed?(key)
|
|
729
|
+
false
|
|
730
|
+
end
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
734
|
+
user_params = params.require(:user)
|
|
735
|
+
|
|
736
|
+
assert_raises(ArgumentError) do
|
|
737
|
+
user_params.transform_params(user_params_class, invalid_key: 'value')
|
|
738
|
+
end
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
def test_transform_params_with_nil_class
|
|
742
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
743
|
+
user_params = params.require(:user)
|
|
744
|
+
permitted = user_params.transform_params(nil)
|
|
745
|
+
|
|
746
|
+
assert_equal({}, permitted.to_h)
|
|
747
|
+
assert permitted.permitted?
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
def test_transform_params_without_required_key
|
|
751
|
+
params = StrongParameters::Core::Parameters.new(name: 'John')
|
|
752
|
+
permitted = params.transform_params
|
|
753
|
+
|
|
754
|
+
assert_equal({}, permitted.to_h)
|
|
755
|
+
assert permitted.permitted?
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
def test_transform_params_with_unregistered_params_class
|
|
759
|
+
# Ensure no registration for :user
|
|
760
|
+
StrongParameters::Core::ParamsRegistry.clear!
|
|
761
|
+
|
|
762
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
763
|
+
user_params = params.require(:user)
|
|
764
|
+
permitted = user_params.transform_params
|
|
765
|
+
|
|
766
|
+
assert_equal({}, permitted.to_h)
|
|
767
|
+
assert permitted.permitted?
|
|
768
|
+
end
|
|
769
|
+
|
|
770
|
+
def test_transform_params_with_nil_params_class
|
|
771
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
772
|
+
user_params = params.require(:user)
|
|
773
|
+
permitted = user_params.transform_params(nil)
|
|
774
|
+
|
|
775
|
+
assert_equal({}, permitted.to_h)
|
|
776
|
+
assert permitted.permitted?
|
|
777
|
+
end
|
|
778
|
+
|
|
779
|
+
# Test hash access methods
|
|
780
|
+
def test_bracket_accessor_with_symbol
|
|
781
|
+
assert_equal 'John', @params[:name]
|
|
782
|
+
end
|
|
783
|
+
|
|
784
|
+
def test_bracket_accessor_with_string
|
|
785
|
+
assert_equal 'John', @params['name']
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
def test_bracket_accessor_returns_nil_for_missing_key
|
|
789
|
+
assert_nil @params[:nonexistent]
|
|
790
|
+
end
|
|
791
|
+
|
|
792
|
+
def test_bracket_accessor_converts_hash_to_parameters
|
|
793
|
+
profile = @params[:profile]
|
|
794
|
+
assert profile.is_a?(StrongParameters::Core::Parameters)
|
|
795
|
+
assert_equal 'Developer', profile[:bio]
|
|
796
|
+
end
|
|
797
|
+
|
|
798
|
+
def test_bracket_equals_sets_value
|
|
799
|
+
@params[:new_key] = 'new_value'
|
|
800
|
+
assert_equal 'new_value', @params[:new_key]
|
|
801
|
+
end
|
|
802
|
+
|
|
803
|
+
def test_bracket_equals_normalizes_key
|
|
804
|
+
@params['new_key'] = 'new_value'
|
|
805
|
+
assert_equal 'new_value', @params[:new_key]
|
|
806
|
+
end
|
|
807
|
+
|
|
808
|
+
def test_fetch_returns_value_when_present
|
|
809
|
+
assert_equal 'John', @params.fetch(:name)
|
|
810
|
+
end
|
|
811
|
+
|
|
812
|
+
def test_fetch_raises_when_key_missing
|
|
813
|
+
assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
814
|
+
@params.fetch(:nonexistent)
|
|
815
|
+
end
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
def test_fetch_with_default_value
|
|
819
|
+
result = @params.fetch(:nonexistent, 'default')
|
|
820
|
+
assert_equal 'default', result
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
def test_fetch_with_block
|
|
824
|
+
result = @params.fetch(:nonexistent) { 'from block' }
|
|
825
|
+
assert_equal 'from block', result
|
|
826
|
+
end
|
|
827
|
+
|
|
828
|
+
def test_fetch_converts_hash_to_parameters
|
|
829
|
+
profile = @params.fetch(:profile)
|
|
830
|
+
assert profile.is_a?(StrongParameters::Core::Parameters)
|
|
831
|
+
end
|
|
832
|
+
|
|
833
|
+
def test_has_key_with_symbol
|
|
834
|
+
assert @params.has_key?(:name)
|
|
835
|
+
end
|
|
836
|
+
|
|
837
|
+
def test_has_key_with_string
|
|
838
|
+
assert @params.has_key?('name')
|
|
839
|
+
end
|
|
840
|
+
|
|
841
|
+
def test_has_key_returns_false_for_missing
|
|
842
|
+
assert !@params.has_key?(:nonexistent)
|
|
843
|
+
end
|
|
844
|
+
|
|
845
|
+
def test_key_alias_works
|
|
846
|
+
assert @params.key?(:name)
|
|
847
|
+
end
|
|
848
|
+
|
|
849
|
+
def test_include_alias_works
|
|
850
|
+
assert @params.include?(:name)
|
|
851
|
+
end
|
|
852
|
+
|
|
853
|
+
def test_delete_removes_key
|
|
854
|
+
@params.delete(:name)
|
|
855
|
+
assert_nil @params[:name]
|
|
856
|
+
end
|
|
857
|
+
|
|
858
|
+
def test_delete_returns_value
|
|
859
|
+
result = @params.delete(:name)
|
|
860
|
+
assert_equal 'John', result
|
|
861
|
+
end
|
|
862
|
+
|
|
863
|
+
def test_delete_normalizes_key
|
|
864
|
+
result = @params.delete('name')
|
|
865
|
+
assert_equal 'John', result
|
|
866
|
+
end
|
|
867
|
+
|
|
868
|
+
def test_bracket_accessor_with_numeric_key
|
|
869
|
+
params = StrongParameters::Core::Parameters.new('123' => 'numeric')
|
|
870
|
+
assert_equal 'numeric', params[123]
|
|
871
|
+
assert_equal 'numeric', params['123']
|
|
872
|
+
end
|
|
873
|
+
|
|
874
|
+
def test_bracket_accessor_with_nil_key
|
|
875
|
+
params = StrongParameters::Core::Parameters.new(nil => 'nil_value')
|
|
876
|
+
assert_equal 'nil_value', params[nil]
|
|
877
|
+
assert_equal 'nil_value', params['']
|
|
878
|
+
end
|
|
879
|
+
|
|
880
|
+
def test_bracket_accessor_with_boolean_key
|
|
881
|
+
params = StrongParameters::Core::Parameters.new(true => 'true_value', false => 'false_value')
|
|
882
|
+
assert_equal 'true_value', params[true]
|
|
883
|
+
assert_equal 'false_value', params[false]
|
|
884
|
+
end
|
|
885
|
+
|
|
886
|
+
def test_bracket_equals_with_numeric_key
|
|
887
|
+
params = StrongParameters::Core::Parameters.new
|
|
888
|
+
params[123] = 'numeric_value'
|
|
889
|
+
assert_equal 'numeric_value', params['123']
|
|
890
|
+
assert_equal 'numeric_value', params[123]
|
|
891
|
+
end
|
|
892
|
+
|
|
893
|
+
def test_bracket_equals_with_nil_key
|
|
894
|
+
params = StrongParameters::Core::Parameters.new
|
|
895
|
+
params[nil] = 'nil_value'
|
|
896
|
+
assert_equal 'nil_value', params['']
|
|
897
|
+
end
|
|
898
|
+
|
|
899
|
+
def test_fetch_with_numeric_key
|
|
900
|
+
params = StrongParameters::Core::Parameters.new('42' => 'answer')
|
|
901
|
+
assert_equal 'answer', params.fetch(42)
|
|
902
|
+
end
|
|
903
|
+
|
|
904
|
+
def test_fetch_with_default_proc
|
|
905
|
+
params = StrongParameters::Core::Parameters.new
|
|
906
|
+
result = params.fetch(:missing) { |key| "default_for_#{key}" }
|
|
907
|
+
assert_equal 'default_for_missing', result
|
|
908
|
+
end
|
|
909
|
+
|
|
910
|
+
def test_has_key_with_numeric_key
|
|
911
|
+
params = StrongParameters::Core::Parameters.new('42' => 'answer')
|
|
912
|
+
assert params.has_key?(42)
|
|
913
|
+
assert params.has_key?('42')
|
|
914
|
+
end
|
|
915
|
+
|
|
916
|
+
def test_has_key_with_nil_key
|
|
917
|
+
params = StrongParameters::Core::Parameters.new(nil => 'value')
|
|
918
|
+
assert params.has_key?(nil)
|
|
919
|
+
assert params.has_key?('')
|
|
920
|
+
end
|
|
921
|
+
|
|
922
|
+
def test_delete_with_numeric_key
|
|
923
|
+
params = StrongParameters::Core::Parameters.new('42' => 'answer')
|
|
924
|
+
result = params.delete(42)
|
|
925
|
+
assert_equal 'answer', result
|
|
926
|
+
assert_nil params['42']
|
|
927
|
+
end
|
|
928
|
+
|
|
929
|
+
def test_delete_with_block
|
|
930
|
+
params = StrongParameters::Core::Parameters.new(name: 'John')
|
|
931
|
+
result = params.delete(:missing) { 'not found' }
|
|
932
|
+
assert_equal 'not found', result
|
|
933
|
+
end
|
|
934
|
+
|
|
935
|
+
def test_bracket_accessor_converts_nested_arrays
|
|
936
|
+
params = StrongParameters::Core::Parameters.new(
|
|
937
|
+
items: [
|
|
938
|
+
{ name: 'item1' },
|
|
939
|
+
{ name: 'item2' }
|
|
940
|
+
]
|
|
941
|
+
)
|
|
942
|
+
|
|
943
|
+
items = params[:items]
|
|
944
|
+
assert items.is_a?(Array)
|
|
945
|
+
assert items[0].is_a?(StrongParameters::Core::Parameters)
|
|
946
|
+
assert_equal 'item1', items[0][:name]
|
|
947
|
+
end
|
|
948
|
+
|
|
949
|
+
def test_fetch_converts_nested_arrays
|
|
950
|
+
params = StrongParameters::Core::Parameters.new(
|
|
951
|
+
items: [
|
|
952
|
+
{ name: 'item1' }
|
|
953
|
+
]
|
|
954
|
+
)
|
|
955
|
+
|
|
956
|
+
items = params.fetch(:items)
|
|
957
|
+
assert items.is_a?(Array)
|
|
958
|
+
assert items[0].is_a?(StrongParameters::Core::Parameters)
|
|
959
|
+
end
|
|
960
|
+
|
|
961
|
+
def test_slice_returns_subset
|
|
962
|
+
sliced = @params.slice(:name, :email)
|
|
963
|
+
assert_equal 'John', sliced[:name]
|
|
964
|
+
assert_equal 'john@example.com', sliced[:email]
|
|
965
|
+
assert_nil sliced[:age]
|
|
966
|
+
end
|
|
967
|
+
|
|
968
|
+
def test_slice_preserves_permitted_flag
|
|
969
|
+
@params.permit!
|
|
970
|
+
sliced = @params.slice(:name)
|
|
971
|
+
assert sliced.permitted?
|
|
972
|
+
end
|
|
973
|
+
|
|
974
|
+
def test_slice_preserves_required_key
|
|
975
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'john@example.com' })
|
|
976
|
+
user_params = params.require(:user)
|
|
977
|
+
sliced = user_params.slice(:name)
|
|
978
|
+
assert_equal :user, sliced.required_key
|
|
979
|
+
end
|
|
980
|
+
|
|
981
|
+
def test_slice_returns_new_instance
|
|
982
|
+
sliced = @params.slice(:name)
|
|
983
|
+
refute_equal @params.object_id, sliced.object_id
|
|
984
|
+
end
|
|
985
|
+
|
|
986
|
+
def test_except_excludes_keys
|
|
987
|
+
excepted = @params.except(:name, :email)
|
|
988
|
+
assert_nil excepted[:name]
|
|
989
|
+
assert_nil excepted[:email]
|
|
990
|
+
assert_equal 30, excepted[:age]
|
|
991
|
+
end
|
|
992
|
+
|
|
993
|
+
def test_except_returns_new_instance
|
|
994
|
+
excepted = @params.except(:name)
|
|
995
|
+
refute_equal @params.object_id, excepted.object_id
|
|
996
|
+
end
|
|
997
|
+
|
|
998
|
+
def test_dup_creates_new_instance
|
|
999
|
+
duped = @params.dup
|
|
1000
|
+
refute_equal @params.object_id, duped.object_id
|
|
1001
|
+
end
|
|
1002
|
+
|
|
1003
|
+
def test_dup_preserves_data
|
|
1004
|
+
duped = @params.dup
|
|
1005
|
+
assert_equal 'John', duped[:name]
|
|
1006
|
+
assert_equal 'john@example.com', duped[:email]
|
|
1007
|
+
assert_equal 30, duped[:age]
|
|
1008
|
+
end
|
|
1009
|
+
|
|
1010
|
+
def test_dup_preserves_permitted_flag
|
|
1011
|
+
@params.permit!
|
|
1012
|
+
duped = @params.dup
|
|
1013
|
+
assert duped.permitted?
|
|
1014
|
+
end
|
|
1015
|
+
|
|
1016
|
+
def test_dup_preserves_required_key
|
|
1017
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
1018
|
+
user_params = params.require(:user)
|
|
1019
|
+
duped = user_params.dup
|
|
1020
|
+
assert_equal :user, duped.required_key
|
|
1021
|
+
end
|
|
1022
|
+
|
|
1023
|
+
def test_dup_creates_shallow_copy
|
|
1024
|
+
duped = @params.dup
|
|
1025
|
+
duped[:new_key] = 'new_value'
|
|
1026
|
+
assert_nil @params[:new_key]
|
|
1027
|
+
end
|
|
1028
|
+
|
|
1029
|
+
def test_dup_with_nested_parameters
|
|
1030
|
+
duped = @params.dup
|
|
1031
|
+
duped[:profile][:new_field] = 'new_value'
|
|
1032
|
+
assert_nil @params[:profile][:new_field]
|
|
1033
|
+
end
|
|
1034
|
+
|
|
1035
|
+
def test_slice_with_nonexistent_keys
|
|
1036
|
+
sliced = @params.slice(:name, :nonexistent)
|
|
1037
|
+
assert_equal 'John', sliced[:name]
|
|
1038
|
+
assert_nil sliced[:nonexistent]
|
|
1039
|
+
end
|
|
1040
|
+
|
|
1041
|
+
def test_slice_with_empty_keys
|
|
1042
|
+
sliced = @params.slice
|
|
1043
|
+
assert_equal({}, sliced.to_h)
|
|
1044
|
+
assert !sliced.permitted?
|
|
1045
|
+
end
|
|
1046
|
+
|
|
1047
|
+
def test_slice_with_mixed_key_types
|
|
1048
|
+
params = StrongParameters::Core::Parameters.new('name' => 'John', :age => 30, 'email' => 'test@example.com')
|
|
1049
|
+
sliced = params.slice('name', :age)
|
|
1050
|
+
assert_equal 'John', sliced[:name]
|
|
1051
|
+
assert_equal 30, sliced[:age]
|
|
1052
|
+
assert_nil sliced[:email]
|
|
1053
|
+
end
|
|
1054
|
+
|
|
1055
|
+
def test_except_with_no_keys
|
|
1056
|
+
excepted = @params.except
|
|
1057
|
+
assert_equal @params.to_h, excepted.to_h
|
|
1058
|
+
end
|
|
1059
|
+
|
|
1060
|
+
def test_except_with_all_keys
|
|
1061
|
+
excepted = @params.except(*@params.keys)
|
|
1062
|
+
assert_equal({}, excepted.to_h)
|
|
1063
|
+
end
|
|
1064
|
+
|
|
1065
|
+
def test_except_preserves_permitted_flag
|
|
1066
|
+
@params.permit!
|
|
1067
|
+
excepted = @params.except(:name)
|
|
1068
|
+
assert excepted.permitted?
|
|
1069
|
+
end
|
|
1070
|
+
|
|
1071
|
+
def test_slice_with_nested_parameters
|
|
1072
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1073
|
+
user: { name: 'John', email: 'john@example.com', profile: { bio: 'Developer' } },
|
|
1074
|
+
admin: true
|
|
1075
|
+
)
|
|
1076
|
+
|
|
1077
|
+
sliced = params.slice(:user)
|
|
1078
|
+
assert_equal 'John', sliced[:user][:name]
|
|
1079
|
+
assert_equal 'john@example.com', sliced[:user][:email]
|
|
1080
|
+
assert_equal 'Developer', sliced[:user][:profile][:bio]
|
|
1081
|
+
assert_nil sliced[:admin]
|
|
1082
|
+
end
|
|
1083
|
+
|
|
1084
|
+
def test_except_with_nested_parameters
|
|
1085
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1086
|
+
user: { name: 'John', email: 'john@example.com', profile: { bio: 'Developer' } },
|
|
1087
|
+
admin: true
|
|
1088
|
+
)
|
|
1089
|
+
|
|
1090
|
+
excepted = params.except(:admin)
|
|
1091
|
+
assert_equal 'John', excepted[:user][:name]
|
|
1092
|
+
assert_equal 'john@example.com', excepted[:user][:email]
|
|
1093
|
+
assert_equal 'Developer', excepted[:user][:profile][:bio]
|
|
1094
|
+
assert_nil excepted[:admin]
|
|
1095
|
+
end
|
|
1096
|
+
|
|
1097
|
+
def test_slice_with_array_of_parameters
|
|
1098
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1099
|
+
users: [
|
|
1100
|
+
{ name: 'John', age: 30 },
|
|
1101
|
+
{ name: 'Jane', age: 25 }
|
|
1102
|
+
],
|
|
1103
|
+
total: 2
|
|
1104
|
+
)
|
|
1105
|
+
|
|
1106
|
+
sliced = params.slice(:users)
|
|
1107
|
+
assert_equal 'John', sliced[:users][0][:name]
|
|
1108
|
+
assert_equal 30, sliced[:users][0][:age]
|
|
1109
|
+
assert_equal 'Jane', sliced[:users][1][:name]
|
|
1110
|
+
assert_equal 25, sliced[:users][1][:age]
|
|
1111
|
+
assert_nil sliced[:total]
|
|
1112
|
+
end
|
|
1113
|
+
|
|
1114
|
+
def test_except_with_array_of_parameters
|
|
1115
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1116
|
+
users: [
|
|
1117
|
+
{ name: 'John', age: 30 },
|
|
1118
|
+
{ name: 'Jane', age: 25 }
|
|
1119
|
+
],
|
|
1120
|
+
total: 2
|
|
1121
|
+
)
|
|
1122
|
+
|
|
1123
|
+
excepted = params.except(:total)
|
|
1124
|
+
assert_equal 'John', excepted[:users][0][:name]
|
|
1125
|
+
assert_equal 30, excepted[:users][0][:age]
|
|
1126
|
+
assert_equal 'Jane', excepted[:users][1][:name]
|
|
1127
|
+
assert_equal 25, excepted[:users][1][:age]
|
|
1128
|
+
assert_nil excepted[:total]
|
|
1129
|
+
end
|
|
1130
|
+
|
|
1131
|
+
def test_slice_preserves_required_key_on_nested
|
|
1132
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1133
|
+
company: {
|
|
1134
|
+
employees: [
|
|
1135
|
+
{ name: 'Alice' },
|
|
1136
|
+
{ name: 'Bob' }
|
|
1137
|
+
]
|
|
1138
|
+
}
|
|
1139
|
+
)
|
|
1140
|
+
|
|
1141
|
+
company = params.require(:company)
|
|
1142
|
+
sliced = company.slice(:employees)
|
|
1143
|
+
assert_equal :company, sliced.required_key
|
|
1144
|
+
end
|
|
1145
|
+
|
|
1146
|
+
def test_except_preserves_required_key
|
|
1147
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'john@example.com', admin: true })
|
|
1148
|
+
user_params = params.require(:user)
|
|
1149
|
+
excepted = user_params.except(:admin)
|
|
1150
|
+
assert_equal :user, excepted.required_key
|
|
1151
|
+
end
|
|
1152
|
+
|
|
1153
|
+
def test_slice_with_duplicate_keys
|
|
1154
|
+
params = StrongParameters::Core::Parameters.new(name: 'John', age: 30, name_dup: 'Jane')
|
|
1155
|
+
sliced = params.slice(:name, :name_dup)
|
|
1156
|
+
assert_equal 'John', sliced[:name]
|
|
1157
|
+
assert_equal 'Jane', sliced[:name_dup]
|
|
1158
|
+
end
|
|
1159
|
+
|
|
1160
|
+
def test_except_with_duplicate_keys
|
|
1161
|
+
params = StrongParameters::Core::Parameters.new(name: 'John', age: 30, name_dup: 'Jane')
|
|
1162
|
+
excepted = params.except(:age)
|
|
1163
|
+
assert_equal 'John', excepted[:name]
|
|
1164
|
+
assert_equal 'Jane', excepted[:name_dup]
|
|
1165
|
+
end
|
|
1166
|
+
|
|
1167
|
+
def test_dup_with_empty_params
|
|
1168
|
+
params = StrongParameters::Core::Parameters.new
|
|
1169
|
+
duped = params.dup
|
|
1170
|
+
assert_equal({}, duped.to_h)
|
|
1171
|
+
assert !duped.permitted?
|
|
1172
|
+
end
|
|
1173
|
+
|
|
1174
|
+
def test_dup_independence_after_modification
|
|
1175
|
+
duped = @params.dup
|
|
1176
|
+
duped[:new_key] = 'new_value'
|
|
1177
|
+
duped.delete(:name)
|
|
1178
|
+
assert_nil @params[:new_key]
|
|
1179
|
+
assert_equal 'John', @params[:name]
|
|
1180
|
+
end
|
|
1181
|
+
|
|
1182
|
+
# Test conversion methods
|
|
1183
|
+
def test_to_h_returns_hash
|
|
1184
|
+
hash = @params.to_h
|
|
1185
|
+
assert hash.is_a?(Hash)
|
|
1186
|
+
end
|
|
1187
|
+
|
|
1188
|
+
def test_to_h_with_permitted_params
|
|
1189
|
+
permitted = @params.permit(:name, :email)
|
|
1190
|
+
hash = permitted.to_h
|
|
1191
|
+
assert_equal 'John', hash['name']
|
|
1192
|
+
assert_equal 'john@example.com', hash['email']
|
|
1193
|
+
end
|
|
1194
|
+
|
|
1195
|
+
def test_to_h_converts_nested_parameters
|
|
1196
|
+
hash = @params.to_h
|
|
1197
|
+
assert hash['profile'].is_a?(Hash)
|
|
1198
|
+
assert_equal 'Developer', hash['profile']['bio']
|
|
1199
|
+
end
|
|
1200
|
+
|
|
1201
|
+
def test_to_unsafe_h_alias
|
|
1202
|
+
assert_equal @params.to_h, @params.to_unsafe_h
|
|
1203
|
+
end
|
|
1204
|
+
|
|
1205
|
+
def test_to_hash_alias
|
|
1206
|
+
assert_equal @params.to_h, @params.to_hash
|
|
1207
|
+
end
|
|
1208
|
+
|
|
1209
|
+
def test_to_h_with_deeply_nested_parameters
|
|
1210
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1211
|
+
user: {
|
|
1212
|
+
profile: {
|
|
1213
|
+
settings: {
|
|
1214
|
+
theme: 'dark',
|
|
1215
|
+
notifications: {
|
|
1216
|
+
email: true,
|
|
1217
|
+
sms: false
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
)
|
|
1223
|
+
hash = params.to_h
|
|
1224
|
+
assert hash.is_a?(Hash)
|
|
1225
|
+
assert_equal 'dark', hash['user']['profile']['settings']['theme']
|
|
1226
|
+
assert_equal true, hash['user']['profile']['settings']['notifications']['email']
|
|
1227
|
+
end
|
|
1228
|
+
|
|
1229
|
+
def test_to_h_with_arrays_of_parameters
|
|
1230
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1231
|
+
users: [
|
|
1232
|
+
{ name: 'John', age: 30 },
|
|
1233
|
+
{ name: 'Jane', age: 25 }
|
|
1234
|
+
]
|
|
1235
|
+
)
|
|
1236
|
+
hash = params.to_h
|
|
1237
|
+
assert hash['users'].is_a?(Array)
|
|
1238
|
+
assert hash['users'][0].is_a?(Hash)
|
|
1239
|
+
assert_equal 'John', hash['users'][0]['name']
|
|
1240
|
+
assert_equal 25, hash['users'][1]['age']
|
|
1241
|
+
end
|
|
1242
|
+
|
|
1243
|
+
def test_to_h_with_mixed_types
|
|
1244
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1245
|
+
name: 'John',
|
|
1246
|
+
age: 30,
|
|
1247
|
+
active: true,
|
|
1248
|
+
score: 95.5,
|
|
1249
|
+
tags: ['ruby', 'rails'],
|
|
1250
|
+
metadata: { created_at: Time.now }
|
|
1251
|
+
)
|
|
1252
|
+
hash = params.to_h
|
|
1253
|
+
assert_equal 'John', hash['name']
|
|
1254
|
+
assert_equal 30, hash['age']
|
|
1255
|
+
assert_equal true, hash['active']
|
|
1256
|
+
assert_equal 95.5, hash['score']
|
|
1257
|
+
assert_equal ['ruby', 'rails'], hash['tags']
|
|
1258
|
+
assert hash['metadata'].is_a?(Hash)
|
|
1259
|
+
end
|
|
1260
|
+
|
|
1261
|
+
def test_to_h_with_file_objects
|
|
1262
|
+
file = StringIO.new('content')
|
|
1263
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1264
|
+
name: 'John',
|
|
1265
|
+
avatar: file
|
|
1266
|
+
)
|
|
1267
|
+
hash = params.to_h
|
|
1268
|
+
assert_equal 'John', hash['name']
|
|
1269
|
+
assert_equal file, hash['avatar']
|
|
1270
|
+
end
|
|
1271
|
+
|
|
1272
|
+
def test_to_h_with_big_decimal
|
|
1273
|
+
bd = BigDecimal('1.23')
|
|
1274
|
+
params = StrongParameters::Core::Parameters.new(price: bd)
|
|
1275
|
+
hash = params.to_h
|
|
1276
|
+
assert_equal bd, hash['price']
|
|
1277
|
+
end
|
|
1278
|
+
|
|
1279
|
+
def test_to_h_with_date_objects
|
|
1280
|
+
date = Date.today
|
|
1281
|
+
time = Time.now
|
|
1282
|
+
datetime = DateTime.now
|
|
1283
|
+
|
|
1284
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1285
|
+
birth_date: date,
|
|
1286
|
+
created_at: time,
|
|
1287
|
+
updated_at: datetime
|
|
1288
|
+
)
|
|
1289
|
+
|
|
1290
|
+
hash = params.to_h
|
|
1291
|
+
assert_equal date, hash['birth_date']
|
|
1292
|
+
assert_equal time, hash['created_at']
|
|
1293
|
+
assert_equal datetime, hash['updated_at']
|
|
1294
|
+
end
|
|
1295
|
+
|
|
1296
|
+
def test_to_h_with_permitted_nested_parameters
|
|
1297
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1298
|
+
user: { name: 'John', email: 'john@example.com', admin: true }
|
|
1299
|
+
)
|
|
1300
|
+
|
|
1301
|
+
permitted = params.permit(user: [:name, :email])
|
|
1302
|
+
hash = permitted.to_h
|
|
1303
|
+
|
|
1304
|
+
assert hash['user'].is_a?(Hash)
|
|
1305
|
+
assert_equal 'John', hash['user']['name']
|
|
1306
|
+
assert_equal 'john@example.com', hash['user']['email']
|
|
1307
|
+
assert_nil hash['user']['admin']
|
|
1308
|
+
end
|
|
1309
|
+
|
|
1310
|
+
def test_to_h_with_complex_mixed_structure
|
|
1311
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1312
|
+
company: {
|
|
1313
|
+
name: 'ACME Corp',
|
|
1314
|
+
founded: Date.new(2000, 1, 1),
|
|
1315
|
+
employees: [
|
|
1316
|
+
{ name: 'Alice', salary: BigDecimal('50000.00'), active: true },
|
|
1317
|
+
{ name: 'Bob', salary: BigDecimal('60000.00'), active: false }
|
|
1318
|
+
],
|
|
1319
|
+
metadata: {
|
|
1320
|
+
industry: 'Tech',
|
|
1321
|
+
locations: ['NYC', 'LA', 'London']
|
|
1322
|
+
}
|
|
1323
|
+
},
|
|
1324
|
+
report_generated_at: Time.now
|
|
1325
|
+
)
|
|
1326
|
+
|
|
1327
|
+
hash = params.to_h
|
|
1328
|
+
|
|
1329
|
+
assert_equal 'ACME Corp', hash['company']['name']
|
|
1330
|
+
assert hash['company']['founded'].is_a?(Date)
|
|
1331
|
+
assert hash['company']['employees'].is_a?(Array)
|
|
1332
|
+
assert hash['company']['employees'][0].is_a?(Hash)
|
|
1333
|
+
assert_equal 'Alice', hash['company']['employees'][0]['name']
|
|
1334
|
+
assert hash['company']['employees'][0]['salary'].is_a?(BigDecimal)
|
|
1335
|
+
assert_equal true, hash['company']['employees'][0]['active']
|
|
1336
|
+
assert_equal 'Tech', hash['company']['metadata']['industry']
|
|
1337
|
+
assert_equal ['NYC', 'LA', 'London'], hash['company']['metadata']['locations']
|
|
1338
|
+
assert hash['report_generated_at'].is_a?(Time)
|
|
1339
|
+
end
|
|
1340
|
+
|
|
1341
|
+
def test_to_h_preserves_array_structure
|
|
1342
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1343
|
+
matrix: [
|
|
1344
|
+
[1, 2, 3],
|
|
1345
|
+
[4, 5, 6],
|
|
1346
|
+
[7, 8, 9]
|
|
1347
|
+
]
|
|
1348
|
+
)
|
|
1349
|
+
|
|
1350
|
+
hash = params.to_h
|
|
1351
|
+
assert_equal [[1, 2, 3], [4, 5, 6], [7, 8, 9]], hash['matrix']
|
|
1352
|
+
end
|
|
1353
|
+
|
|
1354
|
+
def test_to_h_with_empty_parameters
|
|
1355
|
+
params = StrongParameters::Core::Parameters.new
|
|
1356
|
+
hash = params.to_h
|
|
1357
|
+
assert_equal({}, hash)
|
|
1358
|
+
end
|
|
1359
|
+
|
|
1360
|
+
def test_to_unsafe_h_with_permitted_params
|
|
1361
|
+
permitted = @params.permit(:name, :email)
|
|
1362
|
+
assert_equal permitted.to_h, permitted.to_unsafe_h
|
|
1363
|
+
end
|
|
1364
|
+
|
|
1365
|
+
def test_to_h_preserves_key_types
|
|
1366
|
+
params = StrongParameters::Core::Parameters.new('name' => 'John', :age => 30)
|
|
1367
|
+
hash = params.to_h
|
|
1368
|
+
assert_equal 'John', hash['name']
|
|
1369
|
+
assert_equal 30, hash['age']
|
|
1370
|
+
end
|
|
1371
|
+
|
|
1372
|
+
# Test filtering logic
|
|
1373
|
+
def test_permitted_scalar_with_string
|
|
1374
|
+
assert @params.send(:permitted_scalar?, 'test')
|
|
1375
|
+
end
|
|
1376
|
+
|
|
1377
|
+
def test_permitted_scalar_with_symbol
|
|
1378
|
+
assert @params.send(:permitted_scalar?, :test)
|
|
1379
|
+
end
|
|
1380
|
+
|
|
1381
|
+
def test_permitted_scalar_with_nil
|
|
1382
|
+
assert @params.send(:permitted_scalar?, nil)
|
|
1383
|
+
end
|
|
1384
|
+
|
|
1385
|
+
def test_permitted_scalar_with_numeric
|
|
1386
|
+
assert @params.send(:permitted_scalar?, 42)
|
|
1387
|
+
assert @params.send(:permitted_scalar?, 3.14)
|
|
1388
|
+
assert @params.send(:permitted_scalar?, BigDecimal('1.0'))
|
|
1389
|
+
end
|
|
1390
|
+
|
|
1391
|
+
def test_permitted_scalar_with_boolean
|
|
1392
|
+
assert @params.send(:permitted_scalar?, true)
|
|
1393
|
+
assert @params.send(:permitted_scalar?, false)
|
|
1394
|
+
end
|
|
1395
|
+
|
|
1396
|
+
def test_permitted_scalar_with_date_time
|
|
1397
|
+
assert @params.send(:permitted_scalar?, Date.today)
|
|
1398
|
+
assert @params.send(:permitted_scalar?, Time.now)
|
|
1399
|
+
assert @params.send(:permitted_scalar?, DateTime.now)
|
|
1400
|
+
end
|
|
1401
|
+
|
|
1402
|
+
def test_permitted_scalar_with_file
|
|
1403
|
+
file = StringIO.new('content')
|
|
1404
|
+
assert @params.send(:permitted_scalar?, file)
|
|
1405
|
+
assert @params.send(:permitted_scalar?, File.open('/dev/null'))
|
|
1406
|
+
end
|
|
1407
|
+
|
|
1408
|
+
def test_permitted_scalar_with_non_permitted
|
|
1409
|
+
assert !@params.send(:permitted_scalar?, [])
|
|
1410
|
+
assert !@params.send(:permitted_scalar?, {})
|
|
1411
|
+
assert !@params.send(:permitted_scalar?, Object.new)
|
|
1412
|
+
end
|
|
1413
|
+
|
|
1414
|
+
def test_array_of_permitted_scalars_with_valid_array
|
|
1415
|
+
assert @params.send(:array_of_permitted_scalars?, ['a', 'b', 1, 2])
|
|
1416
|
+
end
|
|
1417
|
+
|
|
1418
|
+
def test_array_of_permitted_scalars_with_invalid_array
|
|
1419
|
+
assert !@params.send(:array_of_permitted_scalars?, ['a', {}])
|
|
1420
|
+
end
|
|
1421
|
+
|
|
1422
|
+
def test_array_of_permitted_scalars_with_non_array
|
|
1423
|
+
assert_nil @params.send(:array_of_permitted_scalars?, 'not array')
|
|
1424
|
+
end
|
|
1425
|
+
|
|
1426
|
+
# Test private methods
|
|
1427
|
+
def test_normalize_key
|
|
1428
|
+
params = StrongParameters::Core::Parameters.new
|
|
1429
|
+
assert_equal 'test_key', params.send(:normalize_key, :test_key)
|
|
1430
|
+
assert_equal 'test_key', params.send(:normalize_key, 'test_key')
|
|
1431
|
+
end
|
|
1432
|
+
|
|
1433
|
+
def test_deep_normalize_keys
|
|
1434
|
+
params = StrongParameters::Core::Parameters.new
|
|
1435
|
+
hash = { 'key1' => 'value1', :key2 => { 'nested' => 'value2' } }
|
|
1436
|
+
normalized = params.send(:deep_normalize_keys, hash)
|
|
1437
|
+
assert_equal 'value1', normalized['key1']
|
|
1438
|
+
assert_equal 'value2', normalized['key2']['nested']
|
|
1439
|
+
end
|
|
1440
|
+
|
|
1441
|
+
def test_convert_value_with_hash
|
|
1442
|
+
params = StrongParameters::Core::Parameters.new
|
|
1443
|
+
hash = { a: 1 }
|
|
1444
|
+
converted = params.send(:convert_value, hash)
|
|
1445
|
+
assert converted.is_a?(StrongParameters::Core::Parameters)
|
|
1446
|
+
assert_equal 1, converted[:a]
|
|
1447
|
+
end
|
|
1448
|
+
|
|
1449
|
+
def test_convert_value_with_array
|
|
1450
|
+
params = StrongParameters::Core::Parameters.new
|
|
1451
|
+
array = [{ a: 1 }, { b: 2 }]
|
|
1452
|
+
converted = params.send(:convert_value, array)
|
|
1453
|
+
assert converted[0].is_a?(StrongParameters::Core::Parameters)
|
|
1454
|
+
assert_equal 1, converted[0][:a]
|
|
1455
|
+
end
|
|
1456
|
+
|
|
1457
|
+
def test_wrap_array
|
|
1458
|
+
params = StrongParameters::Core::Parameters.new
|
|
1459
|
+
assert_equal [1], params.send(:wrap_array, 1)
|
|
1460
|
+
assert_equal [1, 2], params.send(:wrap_array, [1, 2])
|
|
1461
|
+
end
|
|
1462
|
+
|
|
1463
|
+
def test_fields_for_style?
|
|
1464
|
+
params = StrongParameters::Core::Parameters.new
|
|
1465
|
+
assert params.send(:fields_for_style?, { '0' => { name: 'John' }, '1' => { name: 'Jane' } })
|
|
1466
|
+
assert !params.send(:fields_for_style?, { name: 'John', age: 30 })
|
|
1467
|
+
end
|
|
1468
|
+
|
|
1469
|
+
def test_fields_for_style_with_negative_indices
|
|
1470
|
+
params = StrongParameters::Core::Parameters.new
|
|
1471
|
+
assert params.send(:fields_for_style?, { '-1' => { name: 'John' }, '0' => { name: 'Jane' } })
|
|
1472
|
+
end
|
|
1473
|
+
|
|
1474
|
+
def test_fields_for_style_with_non_numeric_keys
|
|
1475
|
+
params = StrongParameters::Core::Parameters.new
|
|
1476
|
+
assert !params.send(:fields_for_style?, { 'a' => { name: 'John' }, 'b' => { name: 'Jane' } })
|
|
1477
|
+
end
|
|
1478
|
+
|
|
1479
|
+
def test_fields_for_style_with_mixed_keys
|
|
1480
|
+
params = StrongParameters::Core::Parameters.new
|
|
1481
|
+
assert !params.send(:fields_for_style?, { '0' => { name: 'John' }, 'name' => 'Jane' })
|
|
1482
|
+
end
|
|
1483
|
+
|
|
1484
|
+
def test_convert_value_with_nil
|
|
1485
|
+
params = StrongParameters::Core::Parameters.new
|
|
1486
|
+
assert_nil params.send(:convert_value, nil)
|
|
1487
|
+
end
|
|
1488
|
+
|
|
1489
|
+
def test_convert_value_with_scalar
|
|
1490
|
+
params = StrongParameters::Core::Parameters.new
|
|
1491
|
+
assert_equal 'string', params.send(:convert_value, 'string')
|
|
1492
|
+
assert_equal 42, params.send(:convert_value, 42)
|
|
1493
|
+
end
|
|
1494
|
+
|
|
1495
|
+
def test_convert_value_with_nested_array
|
|
1496
|
+
params = StrongParameters::Core::Parameters.new
|
|
1497
|
+
array = [{ a: 1 }, { b: 2 }]
|
|
1498
|
+
converted = params.send(:convert_value, array)
|
|
1499
|
+
assert converted[0].is_a?(StrongParameters::Core::Parameters)
|
|
1500
|
+
assert_equal 1, converted[0][:a]
|
|
1501
|
+
end
|
|
1502
|
+
|
|
1503
|
+
def test_wrap_array_with_array
|
|
1504
|
+
params = StrongParameters::Core::Parameters.new
|
|
1505
|
+
assert_equal [1, 2, 3], params.send(:wrap_array, [1, 2, 3])
|
|
1506
|
+
end
|
|
1507
|
+
|
|
1508
|
+
def test_wrap_array_with_non_array
|
|
1509
|
+
params = StrongParameters::Core::Parameters.new
|
|
1510
|
+
assert_equal ['string'], params.send(:wrap_array, 'string')
|
|
1511
|
+
assert_equal [42], params.send(:wrap_array, 42)
|
|
1512
|
+
end
|
|
1513
|
+
|
|
1514
|
+
def test_unpermitted_keys_excludes_never_unpermitted
|
|
1515
|
+
params = StrongParameters::Core::Parameters.new(name: 'John', controller: 'users', action: 'create', admin: true)
|
|
1516
|
+
permitted_params = StrongParameters::Core::Parameters.new(name: 'John')
|
|
1517
|
+
unpermitted = params.send(:unpermitted_keys, permitted_params)
|
|
1518
|
+
assert_equal ['admin'], unpermitted
|
|
1519
|
+
assert !unpermitted.include?('controller')
|
|
1520
|
+
assert !unpermitted.include?('action')
|
|
1521
|
+
end
|
|
1522
|
+
|
|
1523
|
+
def test_unpermitted_keys_with_no_permitted
|
|
1524
|
+
params = StrongParameters::Core::Parameters.new(name: 'John', admin: true)
|
|
1525
|
+
permitted_params = StrongParameters::Core::Parameters.new
|
|
1526
|
+
unpermitted = params.send(:unpermitted_keys, permitted_params)
|
|
1527
|
+
assert_equal ['name', 'admin'], unpermitted
|
|
1528
|
+
end
|
|
1529
|
+
|
|
1530
|
+
def test_normalize_key_with_various_types
|
|
1531
|
+
params = StrongParameters::Core::Parameters.new
|
|
1532
|
+
assert_equal '123', params.send(:normalize_key, 123)
|
|
1533
|
+
assert_equal 'true', params.send(:normalize_key, true)
|
|
1534
|
+
assert_equal 'false', params.send(:normalize_key, false)
|
|
1535
|
+
assert_equal '', params.send(:normalize_key, nil)
|
|
1536
|
+
assert_equal 'symbol', params.send(:normalize_key, :symbol)
|
|
1537
|
+
assert_equal 'string', params.send(:normalize_key, 'string')
|
|
1538
|
+
end
|
|
1539
|
+
|
|
1540
|
+
def test_deep_normalize_keys_with_mixed_types
|
|
1541
|
+
params = StrongParameters::Core::Parameters.new
|
|
1542
|
+
hash = {
|
|
1543
|
+
'string' => 'value',
|
|
1544
|
+
:symbol => 'value',
|
|
1545
|
+
123 => 'value',
|
|
1546
|
+
nil => 'value',
|
|
1547
|
+
nested: {
|
|
1548
|
+
'inner_string' => 'value',
|
|
1549
|
+
:inner_symbol => 'value'
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
normalized = params.send(:deep_normalize_keys, hash)
|
|
1554
|
+
assert_equal 'value', normalized['string']
|
|
1555
|
+
assert_equal 'value', normalized['symbol']
|
|
1556
|
+
assert_equal 'value', normalized['123']
|
|
1557
|
+
assert_equal 'value', normalized['']
|
|
1558
|
+
assert_equal 'value', normalized['nested']['inner_string']
|
|
1559
|
+
assert_equal 'value', normalized['nested']['inner_symbol']
|
|
1560
|
+
end
|
|
1561
|
+
|
|
1562
|
+
def test_convert_value_with_deeply_nested_hash
|
|
1563
|
+
params = StrongParameters::Core::Parameters.new
|
|
1564
|
+
hash = { a: { b: { c: 'value' } } }
|
|
1565
|
+
converted = params.send(:convert_value, hash)
|
|
1566
|
+
|
|
1567
|
+
assert converted.is_a?(StrongParameters::Core::Parameters)
|
|
1568
|
+
assert converted[:a].is_a?(StrongParameters::Core::Parameters)
|
|
1569
|
+
assert converted[:a][:b].is_a?(StrongParameters::Core::Parameters)
|
|
1570
|
+
assert_equal 'value', converted[:a][:b][:c]
|
|
1571
|
+
end
|
|
1572
|
+
|
|
1573
|
+
def test_convert_value_with_mixed_array_and_hash
|
|
1574
|
+
params = StrongParameters::Core::Parameters.new
|
|
1575
|
+
mixed = [
|
|
1576
|
+
{ name: 'John' },
|
|
1577
|
+
'string',
|
|
1578
|
+
42,
|
|
1579
|
+
{ nested: { value: true } }
|
|
1580
|
+
]
|
|
1581
|
+
|
|
1582
|
+
converted = params.send(:convert_value, mixed)
|
|
1583
|
+
assert converted[0].is_a?(StrongParameters::Core::Parameters)
|
|
1584
|
+
assert_equal 'John', converted[0][:name]
|
|
1585
|
+
assert_equal 'string', converted[1]
|
|
1586
|
+
assert_equal 42, converted[2]
|
|
1587
|
+
assert converted[3].is_a?(StrongParameters::Core::Parameters)
|
|
1588
|
+
assert_equal true, converted[3][:nested][:value]
|
|
1589
|
+
end
|
|
1590
|
+
|
|
1591
|
+
def test_wrap_array_with_various_inputs
|
|
1592
|
+
params = StrongParameters::Core::Parameters.new
|
|
1593
|
+
assert_equal [nil], params.send(:wrap_array, nil)
|
|
1594
|
+
assert_equal ['string'], params.send(:wrap_array, 'string')
|
|
1595
|
+
assert_equal [42], params.send(:wrap_array, 42)
|
|
1596
|
+
assert_equal [true], params.send(:wrap_array, true)
|
|
1597
|
+
assert_equal [:symbol], params.send(:wrap_array, :symbol)
|
|
1598
|
+
assert_equal([1, 2, 3], params.send(:wrap_array, [1, 2, 3]))
|
|
1599
|
+
end
|
|
1600
|
+
|
|
1601
|
+
def test_fields_for_style_with_various_patterns
|
|
1602
|
+
params = StrongParameters::Core::Parameters.new
|
|
1603
|
+
|
|
1604
|
+
# Valid fields_for patterns
|
|
1605
|
+
assert params.send(:fields_for_style?, { '0' => {}, '1' => {} })
|
|
1606
|
+
assert params.send(:fields_for_style?, { '-1' => {}, '0' => {}, '1' => {} })
|
|
1607
|
+
assert params.send(:fields_for_style?, { '10' => {}, '20' => {} })
|
|
1608
|
+
|
|
1609
|
+
# Invalid patterns
|
|
1610
|
+
assert !params.send(:fields_for_style?, { name: 'John' })
|
|
1611
|
+
assert !params.send(:fields_for_style?, { '0' => {}, name: 'John' })
|
|
1612
|
+
assert !params.send(:fields_for_style?, { 'a' => {}, 'b' => {} })
|
|
1613
|
+
assert !params.send(:fields_for_style?, { '0' => 'not_hash' })
|
|
1614
|
+
assert !params.send(:fields_for_style?, {})
|
|
1615
|
+
end
|
|
1616
|
+
|
|
1617
|
+
def test_unpermitted_keys_with_controller_action
|
|
1618
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1619
|
+
name: 'John',
|
|
1620
|
+
admin: true,
|
|
1621
|
+
controller: 'users',
|
|
1622
|
+
action: 'create'
|
|
1623
|
+
)
|
|
1624
|
+
|
|
1625
|
+
permitted_params = StrongParameters::Core::Parameters.new(name: 'John')
|
|
1626
|
+
unpermitted = params.send(:unpermitted_keys, permitted_params)
|
|
1627
|
+
|
|
1628
|
+
assert_equal ['admin'], unpermitted
|
|
1629
|
+
assert !unpermitted.include?('controller')
|
|
1630
|
+
assert !unpermitted.include?('action')
|
|
1631
|
+
end
|
|
1632
|
+
|
|
1633
|
+
def test_validate_metadata_keys_with_empty_metadata
|
|
1634
|
+
params_class = Class.new(StrongParameters::Core::ApplicationParams)
|
|
1635
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
1636
|
+
user_params = params.require(:user)
|
|
1637
|
+
|
|
1638
|
+
# Should not raise
|
|
1639
|
+
user_params.send(:validate_metadata_keys!, params_class, [])
|
|
1640
|
+
end
|
|
1641
|
+
|
|
1642
|
+
def test_validate_metadata_keys_allows_current_user_always
|
|
1643
|
+
params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
1644
|
+
def self.metadata_allowed?(key)
|
|
1645
|
+
false # Explicitly disallow everything
|
|
1646
|
+
end
|
|
1647
|
+
end
|
|
1648
|
+
|
|
1649
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
1650
|
+
user_params = params.require(:user)
|
|
1651
|
+
|
|
1652
|
+
# Should not raise because :current_user is always allowed
|
|
1653
|
+
user_params.send(:validate_metadata_keys!, params_class, [:current_user])
|
|
1654
|
+
end
|
|
1655
|
+
|
|
1656
|
+
# Test unpermitted parameters handling
|
|
1657
|
+
def test_unpermitted_parameters_with_log_action
|
|
1658
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
|
|
1659
|
+
StrongParameters::Core::Parameters.unpermitted_notification_handler = proc { |keys| @logged_keys = keys }
|
|
1660
|
+
|
|
1661
|
+
params = StrongParameters::Core::Parameters.new(name: 'John', admin: true)
|
|
1662
|
+
params.permit(:name)
|
|
1663
|
+
|
|
1664
|
+
assert_equal ['admin'], @logged_keys
|
|
1665
|
+
end
|
|
1666
|
+
|
|
1667
|
+
def test_unpermitted_parameters_with_raise_action
|
|
1668
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :raise
|
|
1669
|
+
|
|
1670
|
+
params = StrongParameters::Core::Parameters.new(name: 'John', admin: true)
|
|
1671
|
+
|
|
1672
|
+
assert_raises(StrongParameters::Core::UnpermittedParameters) do
|
|
1673
|
+
params.permit(:name)
|
|
1674
|
+
end
|
|
1675
|
+
end
|
|
1676
|
+
|
|
1677
|
+
def test_unpermitted_parameters_with_nil_action
|
|
1678
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = nil
|
|
1679
|
+
|
|
1680
|
+
params = StrongParameters::Core::Parameters.new(name: 'John', admin: true)
|
|
1681
|
+
permitted = params.permit(:name)
|
|
1682
|
+
|
|
1683
|
+
assert_equal 'John', permitted[:name]
|
|
1684
|
+
end
|
|
1685
|
+
|
|
1686
|
+
def test_unpermitted_notification_handler_called_with_correct_keys
|
|
1687
|
+
called_with = nil
|
|
1688
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
|
|
1689
|
+
StrongParameters::Core::Parameters.unpermitted_notification_handler = proc { |keys| called_with = keys }
|
|
1690
|
+
|
|
1691
|
+
params = StrongParameters::Core::Parameters.new(name: 'John', admin: true, secret: 'hidden')
|
|
1692
|
+
params.permit(:name)
|
|
1693
|
+
|
|
1694
|
+
assert_equal ['admin', 'secret'], called_with
|
|
1695
|
+
end
|
|
1696
|
+
|
|
1697
|
+
def test_unpermitted_notification_handler_not_called_when_no_unpermitted
|
|
1698
|
+
called = false
|
|
1699
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
|
|
1700
|
+
StrongParameters::Core::Parameters.unpermitted_notification_handler = proc { called = true }
|
|
1701
|
+
|
|
1702
|
+
params = StrongParameters::Core::Parameters.new(name: 'John')
|
|
1703
|
+
params.permit(:name)
|
|
1704
|
+
|
|
1705
|
+
assert !called
|
|
1706
|
+
end
|
|
1707
|
+
|
|
1708
|
+
def test_unpermitted_notification_handler_with_nil_handler
|
|
1709
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
|
|
1710
|
+
StrongParameters::Core::Parameters.unpermitted_notification_handler = nil
|
|
1711
|
+
|
|
1712
|
+
params = StrongParameters::Core::Parameters.new(name: 'John', admin: true)
|
|
1713
|
+
# Should not raise or error
|
|
1714
|
+
permitted = params.permit(:name)
|
|
1715
|
+
assert_equal 'John', permitted[:name]
|
|
1716
|
+
end
|
|
1717
|
+
|
|
1718
|
+
def test_class_attributes_initially_nil
|
|
1719
|
+
original_action = StrongParameters::Core::Parameters.action_on_unpermitted_parameters
|
|
1720
|
+
original_handler = StrongParameters::Core::Parameters.unpermitted_notification_handler
|
|
1721
|
+
|
|
1722
|
+
begin
|
|
1723
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = nil
|
|
1724
|
+
StrongParameters::Core::Parameters.unpermitted_notification_handler = nil
|
|
1725
|
+
|
|
1726
|
+
assert_nil StrongParameters::Core::Parameters.action_on_unpermitted_parameters
|
|
1727
|
+
assert_nil StrongParameters::Core::Parameters.unpermitted_notification_handler
|
|
1728
|
+
ensure
|
|
1729
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = original_action
|
|
1730
|
+
StrongParameters::Core::Parameters.unpermitted_notification_handler = original_handler
|
|
1731
|
+
end
|
|
1732
|
+
end
|
|
1733
|
+
|
|
1734
|
+
def test_unpermitted_parameters_ignores_controller_and_action
|
|
1735
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :raise
|
|
1736
|
+
|
|
1737
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1738
|
+
name: 'John',
|
|
1739
|
+
controller: 'users',
|
|
1740
|
+
action: 'create'
|
|
1741
|
+
)
|
|
1742
|
+
|
|
1743
|
+
# Should not raise because controller and action are never unpermitted
|
|
1744
|
+
permitted = params.permit(:name)
|
|
1745
|
+
assert_equal 'John', permitted[:name]
|
|
1746
|
+
end
|
|
1747
|
+
|
|
1748
|
+
def test_unpermitted_parameters_with_nested_unpermitted
|
|
1749
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :raise
|
|
1750
|
+
|
|
1751
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1752
|
+
user: {
|
|
1753
|
+
name: 'John',
|
|
1754
|
+
profile: {
|
|
1755
|
+
bio: 'Developer',
|
|
1756
|
+
secret: 'hidden'
|
|
1757
|
+
}
|
|
1758
|
+
},
|
|
1759
|
+
admin: true
|
|
1760
|
+
)
|
|
1761
|
+
|
|
1762
|
+
assert_raises(StrongParameters::Core::UnpermittedParameters) do
|
|
1763
|
+
params.permit(user: [profile: [:bio]]) # secret and admin not permitted
|
|
1764
|
+
end
|
|
1765
|
+
end
|
|
1766
|
+
|
|
1767
|
+
def test_unpermitted_parameters_log_with_custom_handler
|
|
1768
|
+
logged_keys = nil
|
|
1769
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
|
|
1770
|
+
StrongParameters::Core::Parameters.unpermitted_notification_handler = proc { |keys| logged_keys = keys }
|
|
1771
|
+
|
|
1772
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1773
|
+
name: 'John',
|
|
1774
|
+
admin: true,
|
|
1775
|
+
controller: 'users', # Should be ignored
|
|
1776
|
+
action: 'create' # Should be ignored
|
|
1777
|
+
)
|
|
1778
|
+
|
|
1779
|
+
permitted = params.permit(:name)
|
|
1780
|
+
assert_equal 'John', permitted[:name]
|
|
1781
|
+
assert_equal ['admin'], logged_keys
|
|
1782
|
+
end
|
|
1783
|
+
|
|
1784
|
+
def test_unpermitted_parameters_with_multiple_unpermitted_keys
|
|
1785
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
|
|
1786
|
+
logged_keys = nil
|
|
1787
|
+
StrongParameters::Core::Parameters.unpermitted_notification_handler = proc { |keys| logged_keys = keys }
|
|
1788
|
+
|
|
1789
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1790
|
+
name: 'John',
|
|
1791
|
+
admin: true,
|
|
1792
|
+
super_admin: true,
|
|
1793
|
+
secret_token: 'abc123'
|
|
1794
|
+
)
|
|
1795
|
+
|
|
1796
|
+
permitted = params.permit(:name)
|
|
1797
|
+
assert_equal ['admin', 'super_admin', 'secret_token'], logged_keys
|
|
1798
|
+
end
|
|
1799
|
+
|
|
1800
|
+
def test_unpermitted_parameters_with_no_unpermitted_keys
|
|
1801
|
+
called = false
|
|
1802
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
|
|
1803
|
+
StrongParameters::Core::Parameters.unpermitted_notification_handler = proc { called = true }
|
|
1804
|
+
|
|
1805
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1806
|
+
name: 'John',
|
|
1807
|
+
controller: 'users',
|
|
1808
|
+
action: 'create'
|
|
1809
|
+
)
|
|
1810
|
+
|
|
1811
|
+
permitted = params.permit(:name, :controller, :action)
|
|
1812
|
+
assert_equal 'John', permitted[:name]
|
|
1813
|
+
assert !called # Handler should not be called
|
|
1814
|
+
end
|
|
1815
|
+
|
|
1816
|
+
def test_unpermitted_parameters_handler_exception_does_not_prevent_permit
|
|
1817
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :log
|
|
1818
|
+
StrongParameters::Core::Parameters.unpermitted_notification_handler = proc { raise 'Handler error' }
|
|
1819
|
+
|
|
1820
|
+
params = StrongParameters::Core::Parameters.new(name: 'John', admin: true)
|
|
1821
|
+
|
|
1822
|
+
# Even if handler raises, permit should still work
|
|
1823
|
+
permitted = params.permit(:name)
|
|
1824
|
+
assert_equal 'John', permitted[:name]
|
|
1825
|
+
end
|
|
1826
|
+
|
|
1827
|
+
def test_unpermitted_parameters_with_permitted_but_unpermitted_in_nested
|
|
1828
|
+
StrongParameters::Core::Parameters.action_on_unpermitted_parameters = :raise
|
|
1829
|
+
|
|
1830
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1831
|
+
user: {
|
|
1832
|
+
name: 'John',
|
|
1833
|
+
emails: [
|
|
1834
|
+
{ address: 'john@example.com', primary: true },
|
|
1835
|
+
{ address: 'john@work.com', primary: false, secret: 'hidden' }
|
|
1836
|
+
]
|
|
1837
|
+
}
|
|
1838
|
+
)
|
|
1839
|
+
|
|
1840
|
+
assert_raises(StrongParameters::Core::UnpermittedParameters) do
|
|
1841
|
+
params.permit(user: [emails: [:address, :primary]]) # secret not permitted
|
|
1842
|
+
end
|
|
1843
|
+
end
|
|
1844
|
+
|
|
1845
|
+
# Test exceptions
|
|
1846
|
+
def test_parameter_missing_exception_stores_param
|
|
1847
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
1848
|
+
@params.require(:missing)
|
|
1849
|
+
end
|
|
1850
|
+
|
|
1851
|
+
assert_equal 'missing', error.param
|
|
1852
|
+
end
|
|
1853
|
+
|
|
1854
|
+
def test_unpermitted_parameters_exception_stores_params
|
|
1855
|
+
error = StrongParameters::Core::UnpermittedParameters.new(['field1', 'field2'])
|
|
1856
|
+
assert_equal ['field1', 'field2'], error.params
|
|
1857
|
+
end
|
|
1858
|
+
|
|
1859
|
+
def test_parameter_missing_with_empty_available_keys
|
|
1860
|
+
params = StrongParameters::Core::Parameters.new({})
|
|
1861
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
1862
|
+
params.require(:missing)
|
|
1863
|
+
end
|
|
1864
|
+
assert_equal 'missing', error.param
|
|
1865
|
+
assert_match(/param is missing or the value is empty: missing/, error.message)
|
|
1866
|
+
refute_match(/Available keys:/, error.message)
|
|
1867
|
+
refute_match(/Did you mean\?/, error.message)
|
|
1868
|
+
end
|
|
1869
|
+
|
|
1870
|
+
def test_parameter_missing_with_numeric_keys
|
|
1871
|
+
params = StrongParameters::Core::Parameters.new('0' => 'first', '1' => 'second')
|
|
1872
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
1873
|
+
params.require(:missing)
|
|
1874
|
+
end
|
|
1875
|
+
assert_match(/Available keys: 0, 1/, error.message)
|
|
1876
|
+
end
|
|
1877
|
+
|
|
1878
|
+
def test_parameter_missing_with_special_characters_in_keys
|
|
1879
|
+
params = StrongParameters::Core::Parameters.new('user-name' => 'John', 'user_name' => 'Jane')
|
|
1880
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
1881
|
+
params.require(:user)
|
|
1882
|
+
end
|
|
1883
|
+
assert_match(/Did you mean\? user-name, user_name/, error.message)
|
|
1884
|
+
end
|
|
1885
|
+
|
|
1886
|
+
def test_parameter_missing_find_similar_keys_case_insensitive
|
|
1887
|
+
params = StrongParameters::Core::Parameters.new('User' => 'John', 'USER' => 'Jane')
|
|
1888
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
1889
|
+
params.require(:user)
|
|
1890
|
+
end
|
|
1891
|
+
assert_match(/Did you mean\? User, USER/, error.message)
|
|
1892
|
+
end
|
|
1893
|
+
|
|
1894
|
+
def test_unpermitted_parameters_with_empty_keys
|
|
1895
|
+
error = StrongParameters::Core::UnpermittedParameters.new([])
|
|
1896
|
+
assert_equal [], error.params
|
|
1897
|
+
assert_equal "found unpermitted parameters: ", error.message
|
|
1898
|
+
end
|
|
1899
|
+
|
|
1900
|
+
def test_unpermitted_parameters_with_single_key
|
|
1901
|
+
error = StrongParameters::Core::UnpermittedParameters.new(['admin'])
|
|
1902
|
+
assert_equal ['admin'], error.params
|
|
1903
|
+
assert_equal "found unpermitted parameters: admin", error.message
|
|
1904
|
+
end
|
|
1905
|
+
|
|
1906
|
+
def test_parameter_missing_with_no_available_keys
|
|
1907
|
+
params = StrongParameters::Core::Parameters.new({})
|
|
1908
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
1909
|
+
params.require(:user)
|
|
1910
|
+
end
|
|
1911
|
+
|
|
1912
|
+
assert_equal 'user', error.param
|
|
1913
|
+
assert_match(/param is missing or the value is empty: user/, error.message)
|
|
1914
|
+
refute_match(/Available keys:/, error.message)
|
|
1915
|
+
refute_match(/Did you mean\?/, error.message)
|
|
1916
|
+
end
|
|
1917
|
+
|
|
1918
|
+
def test_parameter_missing_with_many_available_keys
|
|
1919
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1920
|
+
usr: 'value',
|
|
1921
|
+
user_name: 'value',
|
|
1922
|
+
user_email: 'value',
|
|
1923
|
+
username: 'value',
|
|
1924
|
+
usr_profile: 'value',
|
|
1925
|
+
other_key: 'value',
|
|
1926
|
+
another_key: 'value'
|
|
1927
|
+
)
|
|
1928
|
+
|
|
1929
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
1930
|
+
params.require(:user)
|
|
1931
|
+
end
|
|
1932
|
+
|
|
1933
|
+
assert_match(/Available keys: usr, user_name, user_email, username, usr_profile, other_key, another_key/, error.message)
|
|
1934
|
+
# Should suggest up to 3 similar keys
|
|
1935
|
+
assert_match(/Did you mean\? usr, user_name, user_email/, error.message)
|
|
1936
|
+
end
|
|
1937
|
+
|
|
1938
|
+
def test_parameter_missing_with_exact_match_suggestion
|
|
1939
|
+
params = StrongParameters::Core::Parameters.new(userr: 'value', usr: 'value')
|
|
1940
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
1941
|
+
params.require(:user)
|
|
1942
|
+
end
|
|
1943
|
+
|
|
1944
|
+
assert_match(/Did you mean\? userr, usr/, error.message)
|
|
1945
|
+
end
|
|
1946
|
+
|
|
1947
|
+
def test_parameter_missing_with_case_insensitive_suggestions
|
|
1948
|
+
params = StrongParameters::Core::Parameters.new(User: 'value', USER: 'value', user_name: 'value')
|
|
1949
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
1950
|
+
params.require(:user)
|
|
1951
|
+
end
|
|
1952
|
+
|
|
1953
|
+
assert_match(/Did you mean\? User, USER, user_name/, error.message)
|
|
1954
|
+
end
|
|
1955
|
+
|
|
1956
|
+
def test_parameter_missing_with_numeric_keys_only
|
|
1957
|
+
params = StrongParameters::Core::Parameters.new('0' => 'first', '1' => 'second', '2' => 'third')
|
|
1958
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
1959
|
+
params.require(:user)
|
|
1960
|
+
end
|
|
1961
|
+
|
|
1962
|
+
assert_match(/Available keys: 0, 1, 2/, error.message)
|
|
1963
|
+
refute_match(/Did you mean\?/, error.message) # Numeric keys shouldn't suggest
|
|
1964
|
+
end
|
|
1965
|
+
|
|
1966
|
+
def test_parameter_missing_with_mixed_key_types
|
|
1967
|
+
params = StrongParameters::Core::Parameters.new(
|
|
1968
|
+
'string_key' => 'value',
|
|
1969
|
+
:symbol_key => 'value',
|
|
1970
|
+
42 => 'value'
|
|
1971
|
+
)
|
|
1972
|
+
|
|
1973
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
1974
|
+
params.require(:user)
|
|
1975
|
+
end
|
|
1976
|
+
|
|
1977
|
+
# Keys are normalized to strings
|
|
1978
|
+
assert_match(/Available keys: string_key, symbol_key, 42/, error.message)
|
|
1979
|
+
end
|
|
1980
|
+
|
|
1981
|
+
def test_parameter_missing_with_very_long_key_list
|
|
1982
|
+
# Create many keys to test display
|
|
1983
|
+
keys = {}
|
|
1984
|
+
20.times { |i| keys["key#{i}"] = "value#{i}" }
|
|
1985
|
+
params = StrongParameters::Core::Parameters.new(keys)
|
|
1986
|
+
|
|
1987
|
+
error = assert_raises(StrongParameters::Core::ParameterMissing) do
|
|
1988
|
+
params.require(:user)
|
|
1989
|
+
end
|
|
1990
|
+
|
|
1991
|
+
assert_match(/Available keys: key0, key1, key2, key3, key4, key5, key6, key7, key8, key9, key10, key11, key12, key13, key14, key15, key16, key17, key18, key19/, error.message)
|
|
1992
|
+
end
|
|
1993
|
+
|
|
1994
|
+
def test_unpermitted_parameters_with_multiple_keys_sorted
|
|
1995
|
+
error = StrongParameters::Core::UnpermittedParameters.new(['zebra', 'alpha', 'beta'])
|
|
1996
|
+
assert_equal ['zebra', 'alpha', 'beta'], error.params
|
|
1997
|
+
assert_equal "found unpermitted parameters: zebra, alpha, beta", error.message
|
|
1998
|
+
end
|
|
1999
|
+
|
|
2000
|
+
def test_unpermitted_parameters_with_special_characters
|
|
2001
|
+
error = StrongParameters::Core::UnpermittedParameters.new(['user-name', 'user_name', 'user.name'])
|
|
2002
|
+
assert_equal ['user-name', 'user_name', 'user.name'], error.params
|
|
2003
|
+
assert_equal "found unpermitted parameters: user-name, user_name, user.name", error.message
|
|
2004
|
+
end
|
|
2005
|
+
|
|
2006
|
+
# Test metadata validation
|
|
2007
|
+
def test_validate_metadata_keys_with_allowed_keys
|
|
2008
|
+
params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
2009
|
+
def self.metadata_allowed?(key)
|
|
2010
|
+
key == :current_user
|
|
2011
|
+
end
|
|
2012
|
+
end
|
|
2013
|
+
|
|
2014
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
2015
|
+
user_params = params.require(:user)
|
|
2016
|
+
|
|
2017
|
+
# Should not raise
|
|
2018
|
+
user_params.send(:validate_metadata_keys!, params_class, [:current_user])
|
|
2019
|
+
end
|
|
2020
|
+
|
|
2021
|
+
def test_validate_metadata_keys_with_disallowed_keys
|
|
2022
|
+
params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
2023
|
+
def self.metadata_allowed?(key)
|
|
2024
|
+
false
|
|
2025
|
+
end
|
|
2026
|
+
end
|
|
2027
|
+
|
|
2028
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
2029
|
+
user_params = params.require(:user)
|
|
2030
|
+
|
|
2031
|
+
error = assert_raises(ArgumentError) do
|
|
2032
|
+
user_params.send(:validate_metadata_keys!, params_class, [:invalid_key])
|
|
2033
|
+
end
|
|
2034
|
+
|
|
2035
|
+
assert_match(/Metadata key\(s\) :invalid_key not allowed/, error.message)
|
|
2036
|
+
assert_match(/To fix this, declare them in your params class/, error.message)
|
|
2037
|
+
end
|
|
2038
|
+
|
|
2039
|
+
def test_validate_metadata_keys_allows_current_user_implicitly
|
|
2040
|
+
params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
2041
|
+
def self.metadata_allowed?(key)
|
|
2042
|
+
false # Even if metadata_allowed? returns false for current_user
|
|
2043
|
+
end
|
|
2044
|
+
end
|
|
2045
|
+
|
|
2046
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
2047
|
+
user_params = params.require(:user)
|
|
2048
|
+
|
|
2049
|
+
# Should not raise because :current_user is always allowed
|
|
2050
|
+
user_params.send(:validate_metadata_keys!, params_class, [:current_user])
|
|
2051
|
+
end
|
|
2052
|
+
|
|
2053
|
+
# Test required_key initialization
|
|
2054
|
+
def test_required_key_initially_nil
|
|
2055
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
2056
|
+
assert_nil params.required_key
|
|
2057
|
+
end
|
|
2058
|
+
|
|
2059
|
+
# Test multi-parameter attributes (like Rails date/time selects)
|
|
2060
|
+
def test_permit_multi_parameter_attributes
|
|
2061
|
+
params = StrongParameters::Core::Parameters.new(
|
|
2062
|
+
'birth_date(1i)' => '1990',
|
|
2063
|
+
'birth_date(2i)' => '01',
|
|
2064
|
+
'birth_date(3i)' => '15'
|
|
2065
|
+
)
|
|
2066
|
+
|
|
2067
|
+
permitted = params.permit(:birth_date)
|
|
2068
|
+
assert_equal '1990', permitted['birth_date(1i)']
|
|
2069
|
+
assert_equal '01', permitted['birth_date(2i)']
|
|
2070
|
+
assert_equal '15', permitted['birth_date(3i)']
|
|
2071
|
+
end
|
|
2072
|
+
|
|
2073
|
+
# Test fields_for style parameters (numeric keys for arrays)
|
|
2074
|
+
def test_permit_fields_for_style_parameters
|
|
2075
|
+
params = StrongParameters::Core::Parameters.new(
|
|
2076
|
+
'0' => { name: 'John', age: '30' },
|
|
2077
|
+
'1' => { name: 'Jane', age: '25' }
|
|
2078
|
+
)
|
|
2079
|
+
|
|
2080
|
+
permitted = params.permit('0' => [:name, :age], '1' => [:name, :age])
|
|
2081
|
+
assert_equal 'John', permitted['0'][:name]
|
|
2082
|
+
assert_equal '30', permitted['0'][:age]
|
|
2083
|
+
assert_equal 'Jane', permitted['1'][:name]
|
|
2084
|
+
assert_equal '25', permitted['1'][:age]
|
|
2085
|
+
end
|
|
2086
|
+
|
|
2087
|
+
# Test edge cases
|
|
2088
|
+
def test_permit_with_empty_filters
|
|
2089
|
+
permitted = @params.permit
|
|
2090
|
+
assert_equal({}, permitted.to_h)
|
|
2091
|
+
assert permitted.permitted?
|
|
2092
|
+
end
|
|
2093
|
+
|
|
2094
|
+
def test_permit_with_nonexistent_keys
|
|
2095
|
+
permitted = @params.permit(:nonexistent)
|
|
2096
|
+
assert_equal({}, permitted.to_h)
|
|
2097
|
+
assert permitted.permitted?
|
|
2098
|
+
end
|
|
2099
|
+
|
|
2100
|
+
def test_require_with_nonexistent_key_in_nested_params
|
|
2101
|
+
params = StrongParameters::Core::Parameters.new(user: { profile: { name: 'John' } })
|
|
2102
|
+
user_params = params.require(:user)
|
|
2103
|
+
profile_params = user_params.require(:profile)
|
|
2104
|
+
|
|
2105
|
+
assert_equal 'John', profile_params[:name]
|
|
2106
|
+
end
|
|
2107
|
+
|
|
2108
|
+
def test_require_with_complex_nested_structure
|
|
2109
|
+
params = StrongParameters::Core::Parameters.new(
|
|
2110
|
+
company: {
|
|
2111
|
+
employees: [
|
|
2112
|
+
{ name: 'Alice', role: 'dev' },
|
|
2113
|
+
{ name: 'Bob', role: 'qa' }
|
|
2114
|
+
],
|
|
2115
|
+
address: {
|
|
2116
|
+
street: '123 Main St',
|
|
2117
|
+
city: 'NYC'
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
)
|
|
2121
|
+
|
|
2122
|
+
company_params = params.require(:company)
|
|
2123
|
+
assert company_params.is_a?(StrongParameters::Core::Parameters)
|
|
2124
|
+
|
|
2125
|
+
employees = company_params[:employees]
|
|
2126
|
+
assert employees.is_a?(Array)
|
|
2127
|
+
assert employees[0].is_a?(StrongParameters::Core::Parameters)
|
|
2128
|
+
assert_equal 'Alice', employees[0][:name]
|
|
2129
|
+
|
|
2130
|
+
address = company_params.require(:address)
|
|
2131
|
+
assert_equal '123 Main St', address[:street]
|
|
2132
|
+
end
|
|
2133
|
+
|
|
2134
|
+
def test_require_preserves_required_key_through_nesting
|
|
2135
|
+
params = StrongParameters::Core::Parameters.new(user: { profile: { settings: { theme: 'dark' } } })
|
|
2136
|
+
user_params = params.require(:user)
|
|
2137
|
+
profile_params = user_params.require(:profile)
|
|
2138
|
+
settings_params = profile_params.require(:settings)
|
|
2139
|
+
|
|
2140
|
+
assert_equal :user, user_params.required_key
|
|
2141
|
+
assert_equal :user, profile_params.required_key # Should inherit from parent
|
|
2142
|
+
assert_equal :user, settings_params.required_key
|
|
2143
|
+
end
|
|
2144
|
+
|
|
2145
|
+
def test_transform_params_with_empty_transformations
|
|
2146
|
+
params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
2147
|
+
def self.permitted_attributes(action: nil)
|
|
2148
|
+
[:name]
|
|
2149
|
+
end
|
|
2150
|
+
|
|
2151
|
+
def self.apply_transformations(params, options)
|
|
2152
|
+
params
|
|
2153
|
+
end
|
|
2154
|
+
end
|
|
2155
|
+
|
|
2156
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John', extra: 'value' })
|
|
2157
|
+
user_params = params.require(:user)
|
|
2158
|
+
permitted = user_params.transform_params(params_class)
|
|
2159
|
+
|
|
2160
|
+
assert_equal 'John', permitted[:name]
|
|
2161
|
+
assert_nil permitted[:extra]
|
|
2162
|
+
end
|
|
2163
|
+
|
|
2164
|
+
def test_transform_params_with_nil_permitted_attributes
|
|
2165
|
+
params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
2166
|
+
def self.permitted_attributes(action: nil)
|
|
2167
|
+
nil
|
|
2168
|
+
end
|
|
2169
|
+
end
|
|
2170
|
+
|
|
2171
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
2172
|
+
user_params = params.require(:user)
|
|
2173
|
+
permitted = user_params.transform_params(params_class)
|
|
2174
|
+
|
|
2175
|
+
assert_equal({}, permitted.to_h)
|
|
2176
|
+
assert permitted.permitted?
|
|
2177
|
+
end
|
|
2178
|
+
|
|
2179
|
+
def test_transform_params_with_empty_permitted_attributes
|
|
2180
|
+
params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
2181
|
+
def self.permitted_attributes(action: nil)
|
|
2182
|
+
[]
|
|
2183
|
+
end
|
|
2184
|
+
end
|
|
2185
|
+
|
|
2186
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
2187
|
+
user_params = params.require(:user)
|
|
2188
|
+
permitted = user_params.transform_params(params_class)
|
|
2189
|
+
|
|
2190
|
+
assert_equal({}, permitted.to_h)
|
|
2191
|
+
assert permitted.permitted?
|
|
2192
|
+
end
|
|
2193
|
+
|
|
2194
|
+
def test_transform_params_with_transformation_returning_nil
|
|
2195
|
+
params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
2196
|
+
def self.permitted_attributes(action: nil)
|
|
2197
|
+
[:name]
|
|
2198
|
+
end
|
|
2199
|
+
|
|
2200
|
+
def self.apply_transformations(params, options)
|
|
2201
|
+
nil
|
|
2202
|
+
end
|
|
2203
|
+
end
|
|
2204
|
+
|
|
2205
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
2206
|
+
user_params = params.require(:user)
|
|
2207
|
+
|
|
2208
|
+
permitted = user_params.transform_params(params_class)
|
|
2209
|
+
assert_equal({}, permitted.to_h)
|
|
2210
|
+
assert permitted.permitted?
|
|
2211
|
+
end
|
|
2212
|
+
|
|
2213
|
+
def test_transform_params_with_transformation_returning_non_hash
|
|
2214
|
+
params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
2215
|
+
def self.permitted_attributes(action: nil)
|
|
2216
|
+
[:name]
|
|
2217
|
+
end
|
|
2218
|
+
|
|
2219
|
+
def self.apply_transformations(params, options)
|
|
2220
|
+
'not a hash'
|
|
2221
|
+
end
|
|
2222
|
+
end
|
|
2223
|
+
|
|
2224
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
2225
|
+
user_params = params.require(:user)
|
|
2226
|
+
|
|
2227
|
+
assert_raises(TypeError) do
|
|
2228
|
+
user_params.transform_params(params_class)
|
|
2229
|
+
end
|
|
2230
|
+
end
|
|
2231
|
+
|
|
2232
|
+
def test_transform_params_with_additional_attrs_empty
|
|
2233
|
+
user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
2234
|
+
def self.permitted_attributes(action: nil)
|
|
2235
|
+
[:name]
|
|
2236
|
+
end
|
|
2237
|
+
end
|
|
2238
|
+
|
|
2239
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John', token: 'abc123' })
|
|
2240
|
+
user_params = params.require(:user)
|
|
2241
|
+
permitted = user_params.transform_params(user_params_class, additional_attrs: [])
|
|
2242
|
+
|
|
2243
|
+
assert_equal 'John', permitted[:name]
|
|
2244
|
+
assert_nil permitted[:token]
|
|
2245
|
+
end
|
|
2246
|
+
|
|
2247
|
+
def test_transform_params_with_additional_attrs_overriding
|
|
2248
|
+
user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
2249
|
+
def self.permitted_attributes(action: nil)
|
|
2250
|
+
[:name]
|
|
2251
|
+
end
|
|
2252
|
+
end
|
|
2253
|
+
|
|
2254
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John', token: 'abc123' })
|
|
2255
|
+
user_params = params.require(:user)
|
|
2256
|
+
permitted = user_params.transform_params(user_params_class, additional_attrs: [:name, :token])
|
|
2257
|
+
|
|
2258
|
+
assert_equal 'John', permitted[:name]
|
|
2259
|
+
assert_equal 'abc123', permitted[:token]
|
|
2260
|
+
end
|
|
2261
|
+
|
|
2262
|
+
def test_transform_params_with_unknown_action
|
|
2263
|
+
user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
2264
|
+
def self.permitted_attributes(action: nil)
|
|
2265
|
+
case action
|
|
2266
|
+
when :create
|
|
2267
|
+
[:name, :email]
|
|
2268
|
+
when :update
|
|
2269
|
+
[:name]
|
|
2270
|
+
else
|
|
2271
|
+
[] # Unknown action returns empty
|
|
2272
|
+
end
|
|
2273
|
+
end
|
|
2274
|
+
end
|
|
2275
|
+
|
|
2276
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'john@example.com' })
|
|
2277
|
+
user_params = params.require(:user)
|
|
2278
|
+
permitted = user_params.transform_params(user_params_class, action: :unknown)
|
|
2279
|
+
|
|
2280
|
+
assert_equal({}, permitted.to_h)
|
|
2281
|
+
assert permitted.permitted?
|
|
2282
|
+
end
|
|
2283
|
+
|
|
2284
|
+
def test_transform_params_with_nil_action
|
|
2285
|
+
user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
2286
|
+
def self.permitted_attributes(action: nil)
|
|
2287
|
+
if action.nil?
|
|
2288
|
+
[:name]
|
|
2289
|
+
else
|
|
2290
|
+
[:email]
|
|
2291
|
+
end
|
|
2292
|
+
end
|
|
2293
|
+
end
|
|
2294
|
+
|
|
2295
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'john@example.com' })
|
|
2296
|
+
user_params = params.require(:user)
|
|
2297
|
+
|
|
2298
|
+
# With nil action
|
|
2299
|
+
permitted_nil = user_params.transform_params(user_params_class, action: nil)
|
|
2300
|
+
assert_equal 'John', permitted_nil[:name]
|
|
2301
|
+
assert_nil permitted_nil[:email]
|
|
2302
|
+
|
|
2303
|
+
# With unspecified action (defaults to nil)
|
|
2304
|
+
permitted_default = user_params.transform_params(user_params_class)
|
|
2305
|
+
assert_equal 'John', permitted_default[:name]
|
|
2306
|
+
assert_nil permitted_default[:email]
|
|
2307
|
+
end
|
|
2308
|
+
|
|
2309
|
+
def test_transform_params_with_complex_transformations
|
|
2310
|
+
user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
2311
|
+
allow :name
|
|
2312
|
+
allow :email
|
|
2313
|
+
allow :age
|
|
2314
|
+
allow :full_name
|
|
2315
|
+
|
|
2316
|
+
def self.apply_transformations(params, options)
|
|
2317
|
+
# Normalize email to lowercase
|
|
2318
|
+
if params['email']
|
|
2319
|
+
params = params.merge('email' => params['email'].downcase)
|
|
2320
|
+
end
|
|
2321
|
+
|
|
2322
|
+
# Add computed field
|
|
2323
|
+
full_name = "#{params['name']} (#{params['age']})"
|
|
2324
|
+
params.merge('full_name' => full_name)
|
|
2325
|
+
end
|
|
2326
|
+
end
|
|
2327
|
+
|
|
2328
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'JOHN@EXAMPLE.COM', age: 30, admin: true })
|
|
2329
|
+
user_params = params.require(:user)
|
|
2330
|
+
permitted = user_params.transform_params(user_params_class)
|
|
2331
|
+
|
|
2332
|
+
assert_equal 'John', permitted[:name]
|
|
2333
|
+
assert_equal 'john@example.com', permitted[:email]
|
|
2334
|
+
assert_equal 30, permitted[:age]
|
|
2335
|
+
assert_equal 'John (30)', permitted[:full_name]
|
|
2336
|
+
assert_nil permitted[:admin]
|
|
2337
|
+
end
|
|
2338
|
+
|
|
2339
|
+
def test_transform_params_with_transformation_error
|
|
2340
|
+
user_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
2341
|
+
def self.permitted_attributes(action: nil)
|
|
2342
|
+
[:name]
|
|
2343
|
+
end
|
|
2344
|
+
|
|
2345
|
+
def self.apply_transformations(params, options)
|
|
2346
|
+
raise StandardError, 'Transformation failed'
|
|
2347
|
+
end
|
|
2348
|
+
end
|
|
2349
|
+
|
|
2350
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John' })
|
|
2351
|
+
user_params = params.require(:user)
|
|
2352
|
+
|
|
2353
|
+
assert_raises(StandardError, 'Transformation failed') do
|
|
2354
|
+
user_params.transform_params(user_params_class)
|
|
2355
|
+
end
|
|
2356
|
+
end
|
|
2357
|
+
|
|
2358
|
+
def test_transform_params_with_empty_params_class
|
|
2359
|
+
empty_params_class = Class.new(StrongParameters::Core::ApplicationParams) do
|
|
2360
|
+
def self.permitted_attributes(action: nil)
|
|
2361
|
+
[]
|
|
2362
|
+
end
|
|
2363
|
+
|
|
2364
|
+
def self.apply_transformations(params, options)
|
|
2365
|
+
{}
|
|
2366
|
+
end
|
|
2367
|
+
end
|
|
2368
|
+
|
|
2369
|
+
params = StrongParameters::Core::Parameters.new(user: { name: 'John', email: 'john@example.com' })
|
|
2370
|
+
user_params = params.require(:user)
|
|
2371
|
+
permitted = user_params.transform_params(empty_params_class)
|
|
2372
|
+
|
|
2373
|
+
assert_equal({}, permitted.to_h)
|
|
2374
|
+
assert permitted.permitted?
|
|
2375
|
+
end
|
|
2376
|
+
end
|