actionpack 7.0.4.3 → 7.1.3.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +380 -284
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/abstract_controller/base.rb +20 -11
  6. data/lib/abstract_controller/caching/fragments.rb +2 -0
  7. data/lib/abstract_controller/callbacks.rb +31 -6
  8. data/lib/abstract_controller/deprecator.rb +7 -0
  9. data/lib/abstract_controller/helpers.rb +75 -28
  10. data/lib/abstract_controller/railties/routes_helpers.rb +1 -16
  11. data/lib/abstract_controller/rendering.rb +12 -14
  12. data/lib/abstract_controller/translation.rb +9 -6
  13. data/lib/abstract_controller/url_for.rb +2 -0
  14. data/lib/abstract_controller.rb +6 -0
  15. data/lib/action_controller/api.rb +6 -4
  16. data/lib/action_controller/base.rb +3 -17
  17. data/lib/action_controller/caching.rb +2 -0
  18. data/lib/action_controller/deprecator.rb +7 -0
  19. data/lib/action_controller/form_builder.rb +2 -0
  20. data/lib/action_controller/log_subscriber.rb +16 -4
  21. data/lib/action_controller/metal/basic_implicit_render.rb +3 -1
  22. data/lib/action_controller/metal/conditional_get.rb +121 -123
  23. data/lib/action_controller/metal/content_security_policy.rb +5 -5
  24. data/lib/action_controller/metal/data_streaming.rb +20 -18
  25. data/lib/action_controller/metal/default_headers.rb +2 -0
  26. data/lib/action_controller/metal/etag_with_flash.rb +3 -1
  27. data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
  28. data/lib/action_controller/metal/exceptions.rb +8 -0
  29. data/lib/action_controller/metal/head.rb +9 -7
  30. data/lib/action_controller/metal/helpers.rb +3 -14
  31. data/lib/action_controller/metal/http_authentication.rb +17 -8
  32. data/lib/action_controller/metal/implicit_render.rb +5 -3
  33. data/lib/action_controller/metal/instrumentation.rb +8 -1
  34. data/lib/action_controller/metal/live.rb +25 -1
  35. data/lib/action_controller/metal/mime_responds.rb +2 -2
  36. data/lib/action_controller/metal/params_wrapper.rb +4 -2
  37. data/lib/action_controller/metal/permissions_policy.rb +2 -2
  38. data/lib/action_controller/metal/redirecting.rb +25 -8
  39. data/lib/action_controller/metal/renderers.rb +4 -4
  40. data/lib/action_controller/metal/rendering.rb +114 -9
  41. data/lib/action_controller/metal/request_forgery_protection.rb +144 -53
  42. data/lib/action_controller/metal/rescue.rb +6 -3
  43. data/lib/action_controller/metal/streaming.rb +71 -31
  44. data/lib/action_controller/metal/strong_parameters.rb +158 -101
  45. data/lib/action_controller/metal/url_for.rb +9 -4
  46. data/lib/action_controller/metal.rb +79 -21
  47. data/lib/action_controller/railtie.rb +24 -10
  48. data/lib/action_controller/renderer.rb +99 -85
  49. data/lib/action_controller/test_case.rb +15 -5
  50. data/lib/action_controller.rb +8 -1
  51. data/lib/action_dispatch/constants.rb +32 -0
  52. data/lib/action_dispatch/deprecator.rb +7 -0
  53. data/lib/action_dispatch/http/cache.rb +8 -10
  54. data/lib/action_dispatch/http/content_security_policy.rb +14 -9
  55. data/lib/action_dispatch/http/filter_parameters.rb +14 -28
  56. data/lib/action_dispatch/http/headers.rb +3 -1
  57. data/lib/action_dispatch/http/mime_negotiation.rb +22 -22
  58. data/lib/action_dispatch/http/mime_type.rb +35 -12
  59. data/lib/action_dispatch/http/mime_types.rb +3 -1
  60. data/lib/action_dispatch/http/parameters.rb +1 -1
  61. data/lib/action_dispatch/http/permissions_policy.rb +38 -23
  62. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  63. data/lib/action_dispatch/http/request.rb +63 -30
  64. data/lib/action_dispatch/http/response.rb +80 -63
  65. data/lib/action_dispatch/http/upload.rb +15 -2
  66. data/lib/action_dispatch/journey/formatter.rb +8 -2
  67. data/lib/action_dispatch/journey/path/pattern.rb +14 -14
  68. data/lib/action_dispatch/journey/route.rb +3 -2
  69. data/lib/action_dispatch/journey/router.rb +9 -8
  70. data/lib/action_dispatch/journey/routes.rb +2 -2
  71. data/lib/action_dispatch/log_subscriber.rb +23 -0
  72. data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -6
  73. data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
  74. data/lib/action_dispatch/middleware/callbacks.rb +2 -0
  75. data/lib/action_dispatch/middleware/cookies.rb +85 -102
  76. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -25
  77. data/lib/action_dispatch/middleware/debug_locks.rb +4 -1
  78. data/lib/action_dispatch/middleware/debug_view.rb +7 -2
  79. data/lib/action_dispatch/middleware/exception_wrapper.rb +186 -27
  80. data/lib/action_dispatch/middleware/executor.rb +1 -1
  81. data/lib/action_dispatch/middleware/flash.rb +7 -0
  82. data/lib/action_dispatch/middleware/host_authorization.rb +18 -8
  83. data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
  84. data/lib/action_dispatch/middleware/reloader.rb +7 -5
  85. data/lib/action_dispatch/middleware/remote_ip.rb +21 -20
  86. data/lib/action_dispatch/middleware/request_id.rb +4 -2
  87. data/lib/action_dispatch/middleware/server_timing.rb +4 -4
  88. data/lib/action_dispatch/middleware/session/abstract_store.rb +5 -0
  89. data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
  90. data/lib/action_dispatch/middleware/session/cookie_store.rb +11 -5
  91. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
  92. data/lib/action_dispatch/middleware/show_exceptions.rb +25 -18
  93. data/lib/action_dispatch/middleware/ssl.rb +18 -6
  94. data/lib/action_dispatch/middleware/stack.rb +7 -2
  95. data/lib/action_dispatch/middleware/static.rb +14 -10
  96. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
  97. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +4 -4
  98. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
  99. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -3
  100. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -3
  101. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +7 -7
  102. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
  103. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +17 -0
  104. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +16 -12
  105. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -1
  106. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
  107. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +4 -4
  108. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  109. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
  110. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
  111. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +59 -41
  112. data/lib/action_dispatch/railtie.rb +14 -4
  113. data/lib/action_dispatch/request/session.rb +16 -6
  114. data/lib/action_dispatch/request/utils.rb +8 -3
  115. data/lib/action_dispatch/routing/inspector.rb +54 -6
  116. data/lib/action_dispatch/routing/mapper.rb +58 -24
  117. data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
  118. data/lib/action_dispatch/routing/redirection.rb +15 -6
  119. data/lib/action_dispatch/routing/route_set.rb +52 -22
  120. data/lib/action_dispatch/routing/routes_proxy.rb +10 -15
  121. data/lib/action_dispatch/routing/url_for.rb +26 -22
  122. data/lib/action_dispatch/routing.rb +7 -7
  123. data/lib/action_dispatch/system_test_case.rb +3 -3
  124. data/lib/action_dispatch/system_testing/browser.rb +20 -19
  125. data/lib/action_dispatch/system_testing/driver.rb +14 -22
  126. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +27 -16
  127. data/lib/action_dispatch/testing/assertion_response.rb +1 -1
  128. data/lib/action_dispatch/testing/assertions/response.rb +14 -7
  129. data/lib/action_dispatch/testing/assertions/routing.rb +67 -28
  130. data/lib/action_dispatch/testing/assertions.rb +3 -1
  131. data/lib/action_dispatch/testing/integration.rb +27 -17
  132. data/lib/action_dispatch/testing/request_encoder.rb +4 -1
  133. data/lib/action_dispatch/testing/test_process.rb +4 -3
  134. data/lib/action_dispatch/testing/test_request.rb +1 -1
  135. data/lib/action_dispatch/testing/test_response.rb +23 -9
  136. data/lib/action_dispatch.rb +37 -4
  137. data/lib/action_pack/gem_version.rb +4 -4
  138. data/lib/action_pack/version.rb +1 -1
  139. data/lib/action_pack.rb +1 -1
  140. metadata +65 -29
@@ -4,6 +4,7 @@ require "active_support/core_ext/hash/indifferent_access"
4
4
  require "active_support/core_ext/array/wrap"
5
5
  require "active_support/core_ext/string/filters"
6
6
  require "active_support/core_ext/object/to_query"
7
+ require "active_support/deep_mergeable"
7
8
  require "action_dispatch/http/upload"
8
9
  require "rack/test"
9
10
  require "stringio"
@@ -64,7 +65,14 @@ module ActionController
64
65
  end
65
66
  end
66
67
 
67
- # == Action Controller \Parameters
68
+ # Raised when initializing Parameters with keys that aren't strings or symbols.
69
+ #
70
+ # ActionController::Parameters.new(123 => 456)
71
+ # # => ActionController::InvalidParameterKey: all keys must be Strings or Symbols, got: Integer
72
+ class InvalidParameterKey < ArgumentError
73
+ end
74
+
75
+ # = Action Controller \Parameters
68
76
  #
69
77
  # Allows you to choose which attributes should be permitted for mass updating
70
78
  # and thus prevent accidentally exposing that which shouldn't be exposed.
@@ -92,12 +100,12 @@ module ActionController
92
100
  # * +permit_all_parameters+ - If it's +true+, all the parameters will be
93
101
  # permitted by default. The default is +false+.
94
102
  # * +action_on_unpermitted_parameters+ - Controls behavior when parameters that are not explicitly
95
- # permitted are found. The default value is <tt>:log</tt> in test and development environments,
96
- # +false+ otherwise. The values can be:
103
+ # permitted are found. The default value is <tt>:log</tt> in test and development environments,
104
+ # +false+ otherwise. The values can be:
97
105
  # * +false+ to take no action.
98
106
  # * <tt>:log</tt> to emit an <tt>ActiveSupport::Notifications.instrument</tt> event on the
99
107
  # <tt>unpermitted_parameters.action_controller</tt> topic and log at the DEBUG level.
100
- # * <tt>:raise</tt> to raise a <tt>ActionController::UnpermittedParameters</tt> exception.
108
+ # * <tt>:raise</tt> to raise an ActionController::UnpermittedParameters exception.
101
109
  #
102
110
  # Examples:
103
111
  #
@@ -123,79 +131,82 @@ module ActionController
123
131
  # environment they should only be set once at boot-time and never mutated at
124
132
  # runtime.
125
133
  #
126
- # You can fetch values of <tt>ActionController::Parameters</tt> using either
134
+ # You can fetch values of +ActionController::Parameters+ using either
127
135
  # <tt>:key</tt> or <tt>"key"</tt>.
128
136
  #
129
137
  # params = ActionController::Parameters.new(key: "value")
130
138
  # params[:key] # => "value"
131
139
  # params["key"] # => "value"
132
140
  class Parameters
141
+ include ActiveSupport::DeepMergeable
142
+
133
143
  cattr_accessor :permit_all_parameters, instance_accessor: false, default: false
134
144
 
135
145
  cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
136
146
 
137
147
  ##
138
- # :method: as_json
148
+ # :method: deep_merge
139
149
  #
140
150
  # :call-seq:
141
- # as_json(options=nil)
151
+ # deep_merge(other_hash, &block)
142
152
  #
143
- # Returns a hash that can be used as the JSON representation for the parameters.
144
-
145
- ##
146
- # :method: each_key
153
+ # Returns a new +ActionController::Parameters+ instance with +self+ and +other_hash+ merged recursively.
147
154
  #
148
- # :call-seq:
149
- # each_key()
155
+ # Like with <tt>Hash#merge</tt> in the standard library, a block can be provided
156
+ # to merge values.
150
157
  #
151
- # Calls block once for each key in the parameters, passing the key.
152
- # If no block is given, an enumerator is returned instead.
158
+ #--
159
+ # Implemented by ActiveSupport::DeepMergeable#deep_merge.
153
160
 
154
161
  ##
155
- # :method: empty?
162
+ # :method: deep_merge!
156
163
  #
157
164
  # :call-seq:
158
- # empty?()
165
+ # deep_merge!(other_hash, &block)
159
166
  #
160
- # Returns true if the parameters have no key/value pairs.
167
+ # Same as +#deep_merge+, but modifies +self+.
168
+ #
169
+ #--
170
+ # Implemented by ActiveSupport::DeepMergeable#deep_merge!.
161
171
 
162
172
  ##
163
- # :method: has_key?
173
+ # :method: as_json
164
174
  #
165
175
  # :call-seq:
166
- # has_key?(key)
176
+ # as_json(options=nil)
167
177
  #
168
- # Returns true if the given key is present in the parameters.
178
+ # Returns a hash that can be used as the JSON representation for the parameters.
169
179
 
170
180
  ##
171
- # :method: has_value?
181
+ # :method: each_key
172
182
  #
173
183
  # :call-seq:
174
- # has_value?(value)
184
+ # each_key(&block)
175
185
  #
176
- # Returns true if the given value is present for some key in the parameters.
186
+ # Calls block once for each key in the parameters, passing the key.
187
+ # If no block is given, an enumerator is returned instead.
177
188
 
178
189
  ##
179
- # :method: include?
190
+ # :method: empty?
180
191
  #
181
192
  # :call-seq:
182
- # include?(key)
193
+ # empty?()
183
194
  #
184
- # Returns true if the given key is present in the parameters.
195
+ # Returns true if the parameters have no key/value pairs.
185
196
 
186
197
  ##
187
- # :method: key?
198
+ # :method: exclude?
188
199
  #
189
200
  # :call-seq:
190
- # key?(key)
201
+ # exclude?(key)
191
202
  #
192
- # Returns true if the given key is present in the parameters.
203
+ # Returns true if the given key is not present in the parameters.
193
204
 
194
205
  ##
195
- # :method: member?
206
+ # :method: include?
196
207
  #
197
208
  # :call-seq:
198
- # member?(key)
209
+ # include?(key)
199
210
  #
200
211
  # Returns true if the given key is present in the parameters.
201
212
 
@@ -215,24 +226,13 @@ module ActionController
215
226
  #
216
227
  # Returns the content of the parameters as a string.
217
228
 
218
- ##
219
- # :method: value?
220
- #
221
- # :call-seq:
222
- # value?(value)
223
- #
224
- # Returns true if the given value is present for some key in the parameters.
225
-
226
- ##
227
- # :method: values
228
- #
229
- # :call-seq:
230
- # values()
231
- #
232
- # Returns a new array of the values of the parameters.
233
- delegate :keys, :key?, :has_key?, :member?, :values, :has_value?, :value?, :empty?, :include?,
229
+ delegate :keys, :empty?, :exclude?, :include?,
234
230
  :as_json, :to_s, :each_key, to: :@parameters
235
231
 
232
+ alias_method :has_key?, :include?
233
+ alias_method :key?, :include?
234
+ alias_method :member?, :include?
235
+
236
236
  # By default, never raise an UnpermittedParameters exception if these
237
237
  # params are present. The default includes both 'controller' and 'action'
238
238
  # because they are added by Rails and should be of no concern. One way
@@ -242,13 +242,15 @@ module ActionController
242
242
  # config.action_controller.always_permitted_parameters = %w( controller action format )
243
243
  cattr_accessor :always_permitted_parameters, default: %w( controller action )
244
244
 
245
+ cattr_accessor :allow_deprecated_parameters_hash_equality, default: true, instance_accessor: false
246
+
245
247
  class << self
246
248
  def nested_attribute?(key, value) # :nodoc:
247
249
  /\A-?\d+\z/.match?(key) && (value.is_a?(Hash) || value.is_a?(Parameters))
248
250
  end
249
251
  end
250
252
 
251
- # Returns a new instance of <tt>ActionController::Parameters</tt>.
253
+ # Returns a new +ActionController::Parameters+ instance.
252
254
  # Also, sets the +permitted+ attribute to the default value of
253
255
  # <tt>ActionController::Parameters.permit_all_parameters</tt>.
254
256
  #
@@ -265,6 +267,12 @@ module ActionController
265
267
  # params.permitted? # => true
266
268
  # Person.new(params) # => #<Person id: nil, name: "Francesco">
267
269
  def initialize(parameters = {}, logging_context = {})
270
+ parameters.each_key do |key|
271
+ unless key.is_a?(String) || key.is_a?(Symbol)
272
+ raise InvalidParameterKey, "all keys must be Strings or Symbols, got: #{key.class}"
273
+ end
274
+ end
275
+
268
276
  @parameters = parameters.with_indifferent_access
269
277
  @logging_context = logging_context
270
278
  @permitted = self.class.permit_all_parameters
@@ -276,7 +284,20 @@ module ActionController
276
284
  if other.respond_to?(:permitted?)
277
285
  permitted? == other.permitted? && parameters == other.parameters
278
286
  else
279
- @parameters == other
287
+ if self.class.allow_deprecated_parameters_hash_equality && Hash === other
288
+ ActionController.deprecator.warn <<-WARNING.squish
289
+ Comparing equality between `ActionController::Parameters` and a
290
+ `Hash` is deprecated and will be removed in Rails 7.2. Please only do
291
+ comparisons between instances of `ActionController::Parameters`. If
292
+ you need to compare to a hash, first convert it using
293
+ `ActionController::Parameters#new`.
294
+ To disable the deprecated behavior set
295
+ `Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false`.
296
+ WARNING
297
+ @parameters == other
298
+ else
299
+ super
300
+ end
280
301
  end
281
302
  end
282
303
 
@@ -290,7 +311,7 @@ module ActionController
290
311
  [self.class, @parameters, @permitted].hash
291
312
  end
292
313
 
293
- # Returns a safe <tt>ActiveSupport::HashWithIndifferentAccess</tt>
314
+ # Returns a safe ActiveSupport::HashWithIndifferentAccess
294
315
  # representation of the parameters with all unpermitted keys removed.
295
316
  #
296
317
  # params = ActionController::Parameters.new({
@@ -302,9 +323,9 @@ module ActionController
302
323
  #
303
324
  # safe_params = params.permit(:name)
304
325
  # safe_params.to_h # => {"name"=>"Senjougahara Hitagi"}
305
- def to_h
326
+ def to_h(&block)
306
327
  if permitted?
307
- convert_parameters_to_hashes(@parameters, :to_h)
328
+ convert_parameters_to_hashes(@parameters, :to_h, &block)
308
329
  else
309
330
  raise UnfilteredParameters
310
331
  end
@@ -350,18 +371,15 @@ module ActionController
350
371
  # safe_params.to_query("user")
351
372
  # # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
352
373
  #
353
- # The string pairs "key=value" that conform the query string
374
+ # The string pairs <tt>"key=value"</tt> that conform the query string
354
375
  # are sorted lexicographically in ascending order.
355
- #
356
- # This method is also aliased as +to_param+.
357
376
  def to_query(*args)
358
377
  to_h.to_query(*args)
359
378
  end
360
379
  alias_method :to_param, :to_query
361
380
 
362
- # Returns an unsafe, unfiltered
363
- # <tt>ActiveSupport::HashWithIndifferentAccess</tt> representation of the
364
- # parameters.
381
+ # Returns an unsafe, unfiltered ActiveSupport::HashWithIndifferentAccess
382
+ # representation of the parameters.
365
383
  #
366
384
  # params = ActionController::Parameters.new({
367
385
  # name: "Senjougahara Hitagi",
@@ -397,11 +415,16 @@ module ActionController
397
415
  self
398
416
  end
399
417
 
418
+ # Returns a new array of the values of the parameters.
419
+ def values
420
+ to_enum(:each_value).to_a
421
+ end
422
+
400
423
  # Attribute that keeps track of converted arrays, if any, to avoid double
401
424
  # looping in the common use case permit + mass-assignment. Defined in a
402
425
  # method to instantiate it only if needed.
403
426
  #
404
- # Testing membership still loops, but it's going to be faster than our own
427
+ # \Testing membership still loops, but it's going to be faster than our own
405
428
  # loop that converts values. Also, we are not going to build a new array
406
429
  # object per fetch.
407
430
  def converted_arrays
@@ -449,7 +472,7 @@ module ActionController
449
472
  # ActionController::Parameters.new(person: { name: "Francesco" }).require(:person)
450
473
  # # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
451
474
  #
452
- # Otherwise raises <tt>ActionController::ParameterMissing</tt>:
475
+ # Otherwise raises ActionController::ParameterMissing:
453
476
  #
454
477
  # ActionController::Parameters.new.require(:person)
455
478
  # # ActionController::ParameterMissing: param is missing or the value is empty: person
@@ -501,10 +524,9 @@ module ActionController
501
524
  end
502
525
  end
503
526
 
504
- # Alias of #require.
505
527
  alias :required :require
506
528
 
507
- # Returns a new <tt>ActionController::Parameters</tt> instance that
529
+ # Returns a new +ActionController::Parameters+ instance that
508
530
  # includes only the given +filters+ and sets the +permitted+ attribute
509
531
  # for the object to +true+. This is useful for limiting which attributes
510
532
  # should be allowed for mass updating.
@@ -523,7 +545,7 @@ module ActionController
523
545
  # +:name+ passes if it is a key of +params+ whose associated value is of type
524
546
  # +String+, +Symbol+, +NilClass+, +Numeric+, +TrueClass+, +FalseClass+,
525
547
  # +Date+, +Time+, +DateTime+, +StringIO+, +IO+,
526
- # +ActionDispatch::Http::UploadedFile+ or +Rack::Test::UploadedFile+.
548
+ # ActionDispatch::Http::UploadedFile or +Rack::Test::UploadedFile+.
527
549
  # Otherwise, the key +:name+ is filtered out.
528
550
  #
529
551
  # You may declare that the parameter should be an array of permitted scalars
@@ -645,16 +667,16 @@ module ActionController
645
667
  end
646
668
 
647
669
  # Assigns a value to a given +key+. The given key may still get filtered out
648
- # when +permit+ is called.
670
+ # when #permit is called.
649
671
  def []=(key, value)
650
672
  @parameters[key] = value
651
673
  end
652
674
 
653
675
  # Returns a parameter for the given +key+. If the +key+
654
676
  # can't be found, there are several options: With no other arguments,
655
- # it will raise an <tt>ActionController::ParameterMissing</tt> error;
677
+ # it will raise an ActionController::ParameterMissing error;
656
678
  # if a second argument is given, then that is returned (converted to an
657
- # instance of ActionController::Parameters if possible); if a block
679
+ # instance of +ActionController::Parameters+ if possible); if a block
658
680
  # is given, then that will be run and its result returned.
659
681
  #
660
682
  # params = ActionController::Parameters.new(person: { name: "Francesco" })
@@ -689,7 +711,7 @@ module ActionController
689
711
  @parameters.dig(*keys)
690
712
  end
691
713
 
692
- # Returns a new <tt>ActionController::Parameters</tt> instance that
714
+ # Returns a new +ActionController::Parameters+ instance that
693
715
  # includes only the given +keys+. If the given +keys+
694
716
  # don't exist, returns an empty hash.
695
717
  #
@@ -700,14 +722,14 @@ module ActionController
700
722
  new_instance_with_inherited_permitted_status(@parameters.slice(*keys))
701
723
  end
702
724
 
703
- # Returns current <tt>ActionController::Parameters</tt> instance which
725
+ # Returns the current +ActionController::Parameters+ instance which
704
726
  # contains only the given +keys+.
705
727
  def slice!(*keys)
706
728
  @parameters.slice!(*keys)
707
729
  self
708
730
  end
709
731
 
710
- # Returns a new <tt>ActionController::Parameters</tt> instance that
732
+ # Returns a new +ActionController::Parameters+ instance that
711
733
  # filters out the given +keys+.
712
734
  #
713
735
  # params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
@@ -716,6 +738,7 @@ module ActionController
716
738
  def except(*keys)
717
739
  new_instance_with_inherited_permitted_status(@parameters.except(*keys))
718
740
  end
741
+ alias_method :without, :except
719
742
 
720
743
  # Removes and returns the key/value pairs matching the given keys.
721
744
  #
@@ -726,7 +749,7 @@ module ActionController
726
749
  new_instance_with_inherited_permitted_status(@parameters.extract!(*keys))
727
750
  end
728
751
 
729
- # Returns a new <tt>ActionController::Parameters</tt> with the results of
752
+ # Returns a new +ActionController::Parameters+ instance with the results of
730
753
  # running +block+ once for every value. The keys are unchanged.
731
754
  #
732
755
  # params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
@@ -740,14 +763,14 @@ module ActionController
740
763
  end
741
764
 
742
765
  # Performs values transformation and returns the altered
743
- # <tt>ActionController::Parameters</tt> instance.
766
+ # +ActionController::Parameters+ instance.
744
767
  def transform_values!
745
768
  return to_enum(:transform_values!) unless block_given?
746
769
  @parameters.transform_values! { |v| yield convert_value_to_parameters(v) }
747
770
  self
748
771
  end
749
772
 
750
- # Returns a new <tt>ActionController::Parameters</tt> instance with the
773
+ # Returns a new +ActionController::Parameters+ instance with the
751
774
  # results of running +block+ once for every key. The values are unchanged.
752
775
  def transform_keys(&block)
753
776
  return to_enum(:transform_keys) unless block_given?
@@ -757,14 +780,14 @@ module ActionController
757
780
  end
758
781
 
759
782
  # Performs keys transformation and returns the altered
760
- # <tt>ActionController::Parameters</tt> instance.
783
+ # +ActionController::Parameters+ instance.
761
784
  def transform_keys!(&block)
762
785
  return to_enum(:transform_keys!) unless block_given?
763
786
  @parameters.transform_keys!(&block)
764
787
  self
765
788
  end
766
789
 
767
- # Returns a new <tt>ActionController::Parameters</tt> instance with the
790
+ # Returns a new +ActionController::Parameters+ instance with the
768
791
  # results of running +block+ once for every key. This includes the keys
769
792
  # from the root hash and from all nested hashes and arrays. The values are unchanged.
770
793
  def deep_transform_keys(&block)
@@ -773,9 +796,9 @@ module ActionController
773
796
  )
774
797
  end
775
798
 
776
- # Returns the <tt>ActionController::Parameters</tt> instance changing its keys.
777
- # This includes the keys from the root hash and from all nested hashes and arrays.
778
- # The values are unchanged.
799
+ # Returns the same +ActionController::Parameters+ instance with
800
+ # changed keys. This includes the keys from the root hash and from all
801
+ # nested hashes and arrays. The values are unchanged.
779
802
  def deep_transform_keys!(&block)
780
803
  @parameters.deep_transform_keys!(&block)
781
804
  self
@@ -783,13 +806,13 @@ module ActionController
783
806
 
784
807
  # Deletes a key-value pair from +Parameters+ and returns the value. If
785
808
  # +key+ is not found, returns +nil+ (or, with optional code block, yields
786
- # +key+ and returns the result). Cf. #extract!, which returns the
787
- # corresponding +ActionController::Parameters+ object.
809
+ # +key+ and returns the result). This method is similar to #extract!, which
810
+ # returns the corresponding +ActionController::Parameters+ object.
788
811
  def delete(key, &block)
789
812
  convert_value_to_parameters(@parameters.delete(key, &block))
790
813
  end
791
814
 
792
- # Returns a new instance of <tt>ActionController::Parameters</tt> with only
815
+ # Returns a new +ActionController::Parameters+ instance with only
793
816
  # items that the block evaluates to true.
794
817
  def select(&block)
795
818
  new_instance_with_inherited_permitted_status(@parameters.select(&block))
@@ -802,7 +825,7 @@ module ActionController
802
825
  end
803
826
  alias_method :keep_if, :select!
804
827
 
805
- # Returns a new instance of <tt>ActionController::Parameters</tt> with items
828
+ # Returns a new +ActionController::Parameters+ instance with items
806
829
  # that the block evaluates to true removed.
807
830
  def reject(&block)
808
831
  new_instance_with_inherited_permitted_status(@parameters.reject(&block))
@@ -815,7 +838,7 @@ module ActionController
815
838
  end
816
839
  alias_method :delete_if, :reject!
817
840
 
818
- # Returns a new instance of <tt>ActionController::Parameters</tt> with +nil+ values removed.
841
+ # Returns a new +ActionController::Parameters+ instance with +nil+ values removed.
819
842
  def compact
820
843
  new_instance_with_inherited_permitted_status(@parameters.compact)
821
844
  end
@@ -825,7 +848,7 @@ module ActionController
825
848
  self if @parameters.compact!
826
849
  end
827
850
 
828
- # Returns a new instance of <tt>ActionController::Parameters</tt> without the blank values.
851
+ # Returns a new +ActionController::Parameters+ instance without the blank values.
829
852
  # Uses Object#blank? for determining if a value is blank.
830
853
  def compact_blank
831
854
  reject { |_k, v| v.blank? }
@@ -837,13 +860,20 @@ module ActionController
837
860
  reject! { |_k, v| v.blank? }
838
861
  end
839
862
 
863
+ # Returns true if the given value is present for some key in the parameters.
864
+ def has_value?(value)
865
+ each_value.include?(convert_value_to_parameters(value))
866
+ end
867
+
868
+ alias value? has_value?
869
+
840
870
  # Returns values that were assigned to the given +keys+. Note that all the
841
- # +Hash+ objects will be converted to <tt>ActionController::Parameters</tt>.
871
+ # +Hash+ objects will be converted to +ActionController::Parameters+.
842
872
  def values_at(*keys)
843
873
  convert_value_to_parameters(@parameters.values_at(*keys))
844
874
  end
845
875
 
846
- # Returns a new <tt>ActionController::Parameters</tt> with all keys from
876
+ # Returns a new +ActionController::Parameters+ instance with all keys from
847
877
  # +other_hash+ merged into current hash.
848
878
  def merge(other_hash)
849
879
  new_instance_with_inherited_permitted_status(
@@ -851,15 +881,22 @@ module ActionController
851
881
  )
852
882
  end
853
883
 
854
- # Returns current <tt>ActionController::Parameters</tt> instance with
884
+ ##
885
+ # :call-seq: merge!(other_hash)
886
+ #
887
+ # Returns the current +ActionController::Parameters+ instance with
855
888
  # +other_hash+ merged into current hash.
856
- def merge!(other_hash)
857
- @parameters.merge!(other_hash.to_h)
889
+ def merge!(other_hash, &block)
890
+ @parameters.merge!(other_hash.to_h, &block)
858
891
  self
859
892
  end
860
893
 
861
- # Returns a new <tt>ActionController::Parameters</tt> with all keys from
862
- # current hash merged into +other_hash+.
894
+ def deep_merge?(other_hash) # :nodoc:
895
+ other_hash.is_a?(ActiveSupport::DeepMergeable)
896
+ end
897
+
898
+ # Returns a new +ActionController::Parameters+ instance with all keys
899
+ # from current hash merged into +other_hash+.
863
900
  def reverse_merge(other_hash)
864
901
  new_instance_with_inherited_permitted_status(
865
902
  other_hash.to_h.merge(@parameters)
@@ -867,7 +904,7 @@ module ActionController
867
904
  end
868
905
  alias_method :with_defaults, :reverse_merge
869
906
 
870
- # Returns current <tt>ActionController::Parameters</tt> instance with
907
+ # Returns the current +ActionController::Parameters+ instance with
871
908
  # current hash merged into +other_hash+.
872
909
  def reverse_merge!(other_hash)
873
910
  @parameters.merge!(other_hash.to_h) { |key, left, right| left }
@@ -917,13 +954,29 @@ module ActionController
917
954
  coder.map = { "parameters" => @parameters, "permitted" => @permitted }
918
955
  end
919
956
 
920
- # Returns duplicate of object including all parameters.
957
+ # Returns a duplicate +ActionController::Parameters+ instance with the same permitted parameters.
921
958
  def deep_dup
922
959
  self.class.new(@parameters.deep_dup, @logging_context).tap do |duplicate|
923
960
  duplicate.permitted = @permitted
924
961
  end
925
962
  end
926
963
 
964
+ # Returns parameter value for the given +key+ separated by +delimiter+.
965
+ #
966
+ # params = ActionController::Parameters.new(id: "1_123", tags: "ruby,rails")
967
+ # params.extract_value(:id) # => ["1", "123"]
968
+ # params.extract_value(:tags, delimiter: ",") # => ["ruby", "rails"]
969
+ # params.extract_value(:non_existent_key) # => nil
970
+ #
971
+ # Note that if the given +key+'s value contains blank elements, then
972
+ # the returned array will include empty strings.
973
+ #
974
+ # params = ActionController::Parameters.new(tags: "ruby,rails,,web")
975
+ # params.extract_value(:tags) # => ["ruby", "rails", "", "web"]
976
+ def extract_value(key, delimiter: "_")
977
+ @parameters[key]&.split(delimiter, -1)
978
+ end
979
+
927
980
  protected
928
981
  attr_reader :parameters
929
982
 
@@ -946,14 +999,15 @@ module ActionController
946
999
  end
947
1000
  end
948
1001
 
949
- def convert_parameters_to_hashes(value, using)
1002
+ def convert_parameters_to_hashes(value, using, &block)
950
1003
  case value
951
1004
  when Array
952
1005
  value.map { |v| convert_parameters_to_hashes(v, using) }
953
1006
  when Hash
954
- value.transform_values do |v|
1007
+ transformed = value.transform_values do |v|
955
1008
  convert_parameters_to_hashes(v, using)
956
- end.with_indifferent_access
1009
+ end
1010
+ (block_given? ? transformed.to_h(&block) : transformed).with_indifferent_access
957
1011
  when Parameters
958
1012
  value.send(using)
959
1013
  else
@@ -1024,10 +1078,11 @@ module ActionController
1024
1078
  # This is a list of permitted scalar types that includes the ones
1025
1079
  # supported in XML and JSON requests.
1026
1080
  #
1027
- # This list is in particular used to filter ordinary requests, String goes
1081
+ # This list is in particular used to filter ordinary requests, \String goes
1028
1082
  # as first element to quickly short-circuit the common case.
1029
1083
  #
1030
- # If you modify this collection please update the API of +permit+ above.
1084
+ # If you modify this collection please update the one in the #permit doc
1085
+ # as well.
1031
1086
  PERMITTED_SCALAR_TYPES = [
1032
1087
  String,
1033
1088
  Symbol,
@@ -1083,8 +1138,8 @@ module ActionController
1083
1138
  value.is_a?(Array) || value.is_a?(Parameters)
1084
1139
  end
1085
1140
 
1086
- EMPTY_ARRAY = []
1087
- EMPTY_HASH = {}
1141
+ EMPTY_ARRAY = [] # :nodoc:
1142
+ EMPTY_HASH = {} # :nodoc:
1088
1143
  def hash_filter(params, filter)
1089
1144
  filter = filter.with_indifferent_access
1090
1145
 
@@ -1135,6 +1190,8 @@ module ActionController
1135
1190
  case element
1136
1191
  when ->(e) { permitted_scalar?(e) }
1137
1192
  sanitized << element
1193
+ when Array
1194
+ sanitized << permit_any_in_array(element)
1138
1195
  when Parameters
1139
1196
  sanitized << permit_any_in_parameters(element)
1140
1197
  else
@@ -1150,7 +1207,7 @@ module ActionController
1150
1207
  end
1151
1208
  end
1152
1209
 
1153
- # == Strong \Parameters
1210
+ # = Strong \Parameters
1154
1211
  #
1155
1212
  # It provides an interface for protecting attributes from end-user
1156
1213
  # assignment. This makes Action Controller parameters forbidden
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionController
4
+ # = Action Controller \UrlFor
5
+ #
4
6
  # Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing
5
7
  # the <tt>_routes</tt> method. Otherwise, an exception will be raised.
6
8
  #
7
9
  # In addition to AbstractController::UrlFor, this module accesses the HTTP layer to define
8
10
  # URL options like the +host+. In order to do so, this module requires the host class
9
- # to implement +env+ which needs to be Rack-compatible and +request+
10
- # which is either an instance of ActionDispatch::Request or an object
11
- # that responds to the +host+, +optional_port+, +protocol+, and
12
- # +symbolized_path_parameter+ methods.
11
+ # to implement +env+ which needs to be Rack-compatible, and +request+ which
12
+ # returns an ActionDispatch::Request instance.
13
13
  #
14
14
  # class RootUrl
15
15
  # include ActionController::UrlFor
@@ -27,6 +27,11 @@ module ActionController
27
27
 
28
28
  include AbstractController::UrlFor
29
29
 
30
+ def initialize(...)
31
+ super
32
+ @_url_options = nil
33
+ end
34
+
30
35
  def url_options
31
36
  @_url_options ||= {
32
37
  host: request.host,