actionpack 6.1.7.5 → 7.1.3.1

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.

Potentially problematic release.


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

Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +355 -435
  3. data/MIT-LICENSE +2 -1
  4. data/README.rdoc +6 -7
  5. data/lib/abstract_controller/asset_paths.rb +1 -1
  6. data/lib/abstract_controller/base.rb +33 -37
  7. data/lib/abstract_controller/caching/fragments.rb +4 -2
  8. data/lib/abstract_controller/caching.rb +1 -1
  9. data/lib/abstract_controller/callbacks.rb +50 -11
  10. data/lib/abstract_controller/collector.rb +2 -2
  11. data/lib/abstract_controller/deprecator.rb +7 -0
  12. data/lib/abstract_controller/error.rb +1 -1
  13. data/lib/abstract_controller/helpers.rb +78 -30
  14. data/lib/abstract_controller/logger.rb +1 -1
  15. data/lib/abstract_controller/railties/routes_helpers.rb +3 -16
  16. data/lib/abstract_controller/rendering.rb +12 -14
  17. data/lib/abstract_controller/translation.rb +26 -7
  18. data/lib/abstract_controller/url_for.rb +6 -6
  19. data/lib/abstract_controller.rb +6 -0
  20. data/lib/action_controller/api.rb +12 -10
  21. data/lib/action_controller/base.rb +8 -21
  22. data/lib/action_controller/caching.rb +2 -0
  23. data/lib/action_controller/deprecator.rb +7 -0
  24. data/lib/action_controller/form_builder.rb +4 -2
  25. data/lib/action_controller/log_subscriber.rb +20 -7
  26. data/lib/action_controller/metal/basic_implicit_render.rb +3 -1
  27. data/lib/action_controller/metal/conditional_get.rb +137 -102
  28. data/lib/action_controller/metal/content_security_policy.rb +37 -3
  29. data/lib/action_controller/metal/cookies.rb +1 -1
  30. data/lib/action_controller/metal/data_streaming.rb +25 -31
  31. data/lib/action_controller/metal/default_headers.rb +2 -0
  32. data/lib/action_controller/metal/etag_with_flash.rb +3 -1
  33. data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
  34. data/lib/action_controller/metal/exceptions.rb +27 -30
  35. data/lib/action_controller/metal/flash.rb +6 -2
  36. data/lib/action_controller/metal/head.rb +9 -7
  37. data/lib/action_controller/metal/helpers.rb +5 -16
  38. data/lib/action_controller/metal/http_authentication.rb +78 -42
  39. data/lib/action_controller/metal/implicit_render.rb +5 -3
  40. data/lib/action_controller/metal/instrumentation.rb +62 -50
  41. data/lib/action_controller/metal/live.rb +67 -2
  42. data/lib/action_controller/metal/mime_responds.rb +5 -5
  43. data/lib/action_controller/metal/params_wrapper.rb +24 -13
  44. data/lib/action_controller/metal/permissions_policy.rb +20 -29
  45. data/lib/action_controller/metal/redirecting.rb +96 -23
  46. data/lib/action_controller/metal/renderers.rb +14 -15
  47. data/lib/action_controller/metal/rendering.rb +121 -16
  48. data/lib/action_controller/metal/request_forgery_protection.rb +208 -68
  49. data/lib/action_controller/metal/rescue.rb +7 -4
  50. data/lib/action_controller/metal/streaming.rb +74 -36
  51. data/lib/action_controller/metal/strong_parameters.rb +254 -151
  52. data/lib/action_controller/metal/testing.rb +9 -2
  53. data/lib/action_controller/metal/url_for.rb +10 -5
  54. data/lib/action_controller/metal.rb +89 -34
  55. data/lib/action_controller/railtie.rb +66 -9
  56. data/lib/action_controller/renderer.rb +99 -85
  57. data/lib/action_controller/test_case.rb +42 -11
  58. data/lib/action_controller.rb +10 -6
  59. data/lib/action_dispatch/constants.rb +32 -0
  60. data/lib/action_dispatch/deprecator.rb +7 -0
  61. data/lib/action_dispatch/http/cache.rb +21 -16
  62. data/lib/action_dispatch/http/content_security_policy.rb +122 -44
  63. data/lib/action_dispatch/http/filter_parameters.rb +14 -23
  64. data/lib/action_dispatch/http/headers.rb +3 -1
  65. data/lib/action_dispatch/http/mime_negotiation.rb +25 -15
  66. data/lib/action_dispatch/http/mime_type.rb +43 -22
  67. data/lib/action_dispatch/http/mime_types.rb +3 -1
  68. data/lib/action_dispatch/http/parameters.rb +6 -6
  69. data/lib/action_dispatch/http/permissions_policy.rb +57 -19
  70. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  71. data/lib/action_dispatch/http/request.rb +75 -51
  72. data/lib/action_dispatch/http/response.rb +81 -77
  73. data/lib/action_dispatch/http/upload.rb +15 -2
  74. data/lib/action_dispatch/http/url.rb +11 -19
  75. data/lib/action_dispatch/journey/formatter.rb +8 -2
  76. data/lib/action_dispatch/journey/gtg/builder.rb +11 -12
  77. data/lib/action_dispatch/journey/gtg/simulator.rb +10 -4
  78. data/lib/action_dispatch/journey/gtg/transition_table.rb +77 -21
  79. data/lib/action_dispatch/journey/nodes/node.rb +70 -5
  80. data/lib/action_dispatch/journey/path/pattern.rb +36 -27
  81. data/lib/action_dispatch/journey/route.rb +8 -14
  82. data/lib/action_dispatch/journey/router/utils.rb +2 -2
  83. data/lib/action_dispatch/journey/router.rb +10 -9
  84. data/lib/action_dispatch/journey/routes.rb +5 -5
  85. data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
  86. data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
  87. data/lib/action_dispatch/log_subscriber.rb +23 -0
  88. data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -7
  89. data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
  90. data/lib/action_dispatch/middleware/callbacks.rb +2 -0
  91. data/lib/action_dispatch/middleware/cookies.rb +97 -107
  92. data/lib/action_dispatch/middleware/debug_exceptions.rb +31 -28
  93. data/lib/action_dispatch/middleware/debug_locks.rb +7 -4
  94. data/lib/action_dispatch/middleware/debug_view.rb +7 -2
  95. data/lib/action_dispatch/middleware/exception_wrapper.rb +190 -27
  96. data/lib/action_dispatch/middleware/executor.rb +3 -0
  97. data/lib/action_dispatch/middleware/flash.rb +24 -18
  98. data/lib/action_dispatch/middleware/host_authorization.rb +19 -20
  99. data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
  100. data/lib/action_dispatch/middleware/reloader.rb +7 -5
  101. data/lib/action_dispatch/middleware/remote_ip.rb +32 -19
  102. data/lib/action_dispatch/middleware/request_id.rb +5 -3
  103. data/lib/action_dispatch/middleware/server_timing.rb +76 -0
  104. data/lib/action_dispatch/middleware/session/abstract_store.rb +6 -1
  105. data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
  106. data/lib/action_dispatch/middleware/session/cookie_store.rb +19 -13
  107. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
  108. data/lib/action_dispatch/middleware/show_exceptions.rb +30 -25
  109. data/lib/action_dispatch/middleware/ssl.rb +18 -6
  110. data/lib/action_dispatch/middleware/stack.rb +34 -11
  111. data/lib/action_dispatch/middleware/static.rb +16 -16
  112. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
  113. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +5 -5
  114. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -11
  115. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
  116. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +2 -2
  117. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +10 -5
  118. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +7 -3
  119. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +9 -9
  120. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
  121. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +3 -3
  122. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +45 -18
  123. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -15
  124. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +4 -4
  125. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +6 -6
  126. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +7 -7
  127. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
  128. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
  129. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
  130. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -55
  131. data/lib/action_dispatch/railtie.rb +20 -4
  132. data/lib/action_dispatch/request/session.rb +59 -19
  133. data/lib/action_dispatch/request/utils.rb +8 -3
  134. data/lib/action_dispatch/routing/inspector.rb +55 -7
  135. data/lib/action_dispatch/routing/mapper.rb +117 -107
  136. data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
  137. data/lib/action_dispatch/routing/redirection.rb +20 -8
  138. data/lib/action_dispatch/routing/route_set.rb +67 -27
  139. data/lib/action_dispatch/routing/routes_proxy.rb +11 -16
  140. data/lib/action_dispatch/routing/url_for.rb +29 -26
  141. data/lib/action_dispatch/routing.rb +12 -13
  142. data/lib/action_dispatch/system_test_case.rb +8 -8
  143. data/lib/action_dispatch/system_testing/browser.rb +20 -29
  144. data/lib/action_dispatch/system_testing/driver.rb +34 -18
  145. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +35 -20
  146. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +0 -8
  147. data/lib/action_dispatch/testing/assertion_response.rb +1 -1
  148. data/lib/action_dispatch/testing/assertions/response.rb +14 -7
  149. data/lib/action_dispatch/testing/assertions/routing.rb +70 -30
  150. data/lib/action_dispatch/testing/assertions.rb +3 -4
  151. data/lib/action_dispatch/testing/integration.rb +33 -25
  152. data/lib/action_dispatch/testing/request_encoder.rb +4 -1
  153. data/lib/action_dispatch/testing/test_process.rb +5 -30
  154. data/lib/action_dispatch/testing/test_request.rb +1 -1
  155. data/lib/action_dispatch/testing/test_response.rb +34 -2
  156. data/lib/action_dispatch.rb +38 -4
  157. data/lib/action_pack/gem_version.rb +4 -4
  158. data/lib/action_pack/version.rb +1 -1
  159. data/lib/action_pack.rb +1 -1
  160. metadata +67 -30
@@ -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"
@@ -27,28 +28,13 @@ module ActionController
27
28
  super("param is missing or the value is empty: #{param}")
28
29
  end
29
30
 
30
- class Correction
31
- def initialize(error)
32
- @error = error
33
- end
34
-
35
- def corrections
36
- if @error.param && @error.keys
37
- maybe_these = @error.keys
31
+ if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
32
+ include DidYouMean::Correctable # :nodoc:
38
33
 
39
- maybe_these.sort_by { |n|
40
- DidYouMean::Jaro.distance(@error.param.to_s, n)
41
- }.reverse.first(4)
42
- else
43
- []
44
- end
34
+ def corrections # :nodoc:
35
+ @corrections ||= DidYouMean::SpellChecker.new(dictionary: keys).correct(param.to_s)
45
36
  end
46
37
  end
47
-
48
- # We may not have DYM, and DYM might not let us register error handlers
49
- if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
50
- DidYouMean.correct_error(self, Correction)
51
- end
52
38
  end
53
39
 
54
40
  # Raised when a supplied parameter is not expected and
@@ -79,7 +65,14 @@ module ActionController
79
65
  end
80
66
  end
81
67
 
82
- # == 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
83
76
  #
84
77
  # Allows you to choose which attributes should be permitted for mass updating
85
78
  # and thus prevent accidentally exposing that which shouldn't be exposed.
@@ -96,7 +89,7 @@ module ActionController
96
89
  # })
97
90
  #
98
91
  # permitted = params.require(:person).permit(:name, :age)
99
- # permitted # => <ActionController::Parameters {"name"=>"Francesco", "age"=>22} permitted: true>
92
+ # permitted # => #<ActionController::Parameters {"name"=>"Francesco", "age"=>22} permitted: true>
100
93
  # permitted.permitted? # => true
101
94
  #
102
95
  # Person.first.update!(permitted)
@@ -106,11 +99,13 @@ module ActionController
106
99
  #
107
100
  # * +permit_all_parameters+ - If it's +true+, all the parameters will be
108
101
  # permitted by default. The default is +false+.
109
- # * +action_on_unpermitted_parameters+ - Allow to control the behavior when parameters
110
- # that are not explicitly permitted are found. The values can be +false+ to just filter them
111
- # out, <tt>:log</tt> to additionally write a message on the logger, or <tt>:raise</tt> to raise
112
- # ActionController::UnpermittedParameters exception. The default value is <tt>:log</tt>
113
- # in test and development environments, +false+ otherwise.
102
+ # * +action_on_unpermitted_parameters+ - Controls behavior when parameters that are not explicitly
103
+ # permitted are found. The default value is <tt>:log</tt> in test and development environments,
104
+ # +false+ otherwise. The values can be:
105
+ # * +false+ to take no action.
106
+ # * <tt>:log</tt> to emit an <tt>ActiveSupport::Notifications.instrument</tt> event on the
107
+ # <tt>unpermitted_parameters.action_controller</tt> topic and log at the DEBUG level.
108
+ # * <tt>:raise</tt> to raise an ActionController::UnpermittedParameters exception.
114
109
  #
115
110
  # Examples:
116
111
  #
@@ -124,7 +119,7 @@ module ActionController
124
119
  #
125
120
  # params = ActionController::Parameters.new(a: "123", b: "456")
126
121
  # params.permit(:c)
127
- # # => <ActionController::Parameters {} permitted: true>
122
+ # # => #<ActionController::Parameters {} permitted: true>
128
123
  #
129
124
  # ActionController::Parameters.action_on_unpermitted_parameters = :raise
130
125
  #
@@ -136,79 +131,82 @@ module ActionController
136
131
  # environment they should only be set once at boot-time and never mutated at
137
132
  # runtime.
138
133
  #
139
- # You can fetch values of <tt>ActionController::Parameters</tt> using either
134
+ # You can fetch values of +ActionController::Parameters+ using either
140
135
  # <tt>:key</tt> or <tt>"key"</tt>.
141
136
  #
142
137
  # params = ActionController::Parameters.new(key: "value")
143
138
  # params[:key] # => "value"
144
139
  # params["key"] # => "value"
145
140
  class Parameters
141
+ include ActiveSupport::DeepMergeable
142
+
146
143
  cattr_accessor :permit_all_parameters, instance_accessor: false, default: false
147
144
 
148
145
  cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
149
146
 
150
147
  ##
151
- # :method: as_json
148
+ # :method: deep_merge
152
149
  #
153
150
  # :call-seq:
154
- # as_json(options=nil)
151
+ # deep_merge(other_hash, &block)
155
152
  #
156
- # Returns a hash that can be used as the JSON representation for the parameters.
157
-
158
- ##
159
- # :method: each_key
153
+ # Returns a new +ActionController::Parameters+ instance with +self+ and +other_hash+ merged recursively.
160
154
  #
161
- # :call-seq:
162
- # each_key()
155
+ # Like with <tt>Hash#merge</tt> in the standard library, a block can be provided
156
+ # to merge values.
163
157
  #
164
- # Calls block once for each key in the parameters, passing the key.
165
- # If no block is given, an enumerator is returned instead.
158
+ #--
159
+ # Implemented by ActiveSupport::DeepMergeable#deep_merge.
166
160
 
167
161
  ##
168
- # :method: empty?
162
+ # :method: deep_merge!
169
163
  #
170
164
  # :call-seq:
171
- # empty?()
165
+ # deep_merge!(other_hash, &block)
172
166
  #
173
- # 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!.
174
171
 
175
172
  ##
176
- # :method: has_key?
173
+ # :method: as_json
177
174
  #
178
175
  # :call-seq:
179
- # has_key?(key)
176
+ # as_json(options=nil)
180
177
  #
181
- # 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.
182
179
 
183
180
  ##
184
- # :method: has_value?
181
+ # :method: each_key
185
182
  #
186
183
  # :call-seq:
187
- # has_value?(value)
184
+ # each_key(&block)
188
185
  #
189
- # 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.
190
188
 
191
189
  ##
192
- # :method: include?
190
+ # :method: empty?
193
191
  #
194
192
  # :call-seq:
195
- # include?(key)
193
+ # empty?()
196
194
  #
197
- # Returns true if the given key is present in the parameters.
195
+ # Returns true if the parameters have no key/value pairs.
198
196
 
199
197
  ##
200
- # :method: key?
198
+ # :method: exclude?
201
199
  #
202
200
  # :call-seq:
203
- # key?(key)
201
+ # exclude?(key)
204
202
  #
205
- # Returns true if the given key is present in the parameters.
203
+ # Returns true if the given key is not present in the parameters.
206
204
 
207
205
  ##
208
- # :method: member?
206
+ # :method: include?
209
207
  #
210
208
  # :call-seq:
211
- # member?(key)
209
+ # include?(key)
212
210
  #
213
211
  # Returns true if the given key is present in the parameters.
214
212
 
@@ -228,40 +226,31 @@ module ActionController
228
226
  #
229
227
  # Returns the content of the parameters as a string.
230
228
 
231
- ##
232
- # :method: value?
233
- #
234
- # :call-seq:
235
- # value?(value)
236
- #
237
- # Returns true if the given value is present for some key in the parameters.
238
-
239
- ##
240
- # :method: values
241
- #
242
- # :call-seq:
243
- # values()
244
- #
245
- # Returns a new array of the values of the parameters.
246
- delegate :keys, :key?, :has_key?, :member?, :values, :has_value?, :value?, :empty?, :include?,
229
+ delegate :keys, :empty?, :exclude?, :include?,
247
230
  :as_json, :to_s, :each_key, to: :@parameters
248
231
 
232
+ alias_method :has_key?, :include?
233
+ alias_method :key?, :include?
234
+ alias_method :member?, :include?
235
+
249
236
  # By default, never raise an UnpermittedParameters exception if these
250
237
  # params are present. The default includes both 'controller' and 'action'
251
238
  # because they are added by Rails and should be of no concern. One way
252
- # to change these is to specify `always_permitted_parameters` in your
239
+ # to change these is to specify +always_permitted_parameters+ in your
253
240
  # config. For instance:
254
241
  #
255
242
  # config.action_controller.always_permitted_parameters = %w( controller action format )
256
243
  cattr_accessor :always_permitted_parameters, default: %w( controller action )
257
244
 
245
+ cattr_accessor :allow_deprecated_parameters_hash_equality, default: true, instance_accessor: false
246
+
258
247
  class << self
259
248
  def nested_attribute?(key, value) # :nodoc:
260
249
  /\A-?\d+\z/.match?(key) && (value.is_a?(Hash) || value.is_a?(Parameters))
261
250
  end
262
251
  end
263
252
 
264
- # Returns a new instance of <tt>ActionController::Parameters</tt>.
253
+ # Returns a new +ActionController::Parameters+ instance.
265
254
  # Also, sets the +permitted+ attribute to the default value of
266
255
  # <tt>ActionController::Parameters.permit_all_parameters</tt>.
267
256
  #
@@ -277,8 +266,15 @@ module ActionController
277
266
  # params = ActionController::Parameters.new(name: "Francesco")
278
267
  # params.permitted? # => true
279
268
  # Person.new(params) # => #<Person id: nil, name: "Francesco">
280
- def initialize(parameters = {})
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
+
281
276
  @parameters = parameters.with_indifferent_access
277
+ @logging_context = logging_context
282
278
  @permitted = self.class.permit_all_parameters
283
279
  end
284
280
 
@@ -288,16 +284,34 @@ module ActionController
288
284
  if other.respond_to?(:permitted?)
289
285
  permitted? == other.permitted? && parameters == other.parameters
290
286
  else
291
- @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
292
301
  end
293
302
  end
294
- alias eql? ==
303
+
304
+ def eql?(other)
305
+ self.class == other.class &&
306
+ permitted? == other.permitted? &&
307
+ parameters.eql?(other.parameters)
308
+ end
295
309
 
296
310
  def hash
297
- [@parameters.hash, @permitted].hash
311
+ [self.class, @parameters, @permitted].hash
298
312
  end
299
313
 
300
- # Returns a safe <tt>ActiveSupport::HashWithIndifferentAccess</tt>
314
+ # Returns a safe ActiveSupport::HashWithIndifferentAccess
301
315
  # representation of the parameters with all unpermitted keys removed.
302
316
  #
303
317
  # params = ActionController::Parameters.new({
@@ -309,9 +323,9 @@ module ActionController
309
323
  #
310
324
  # safe_params = params.permit(:name)
311
325
  # safe_params.to_h # => {"name"=>"Senjougahara Hitagi"}
312
- def to_h
326
+ def to_h(&block)
313
327
  if permitted?
314
- convert_parameters_to_hashes(@parameters, :to_h)
328
+ convert_parameters_to_hashes(@parameters, :to_h, &block)
315
329
  else
316
330
  raise UnfilteredParameters
317
331
  end
@@ -357,18 +371,15 @@ module ActionController
357
371
  # safe_params.to_query("user")
358
372
  # # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
359
373
  #
360
- # The string pairs "key=value" that conform the query string
374
+ # The string pairs <tt>"key=value"</tt> that conform the query string
361
375
  # are sorted lexicographically in ascending order.
362
- #
363
- # This method is also aliased as +to_param+.
364
376
  def to_query(*args)
365
377
  to_h.to_query(*args)
366
378
  end
367
379
  alias_method :to_param, :to_query
368
380
 
369
- # Returns an unsafe, unfiltered
370
- # <tt>ActiveSupport::HashWithIndifferentAccess</tt> representation of the
371
- # parameters.
381
+ # Returns an unsafe, unfiltered ActiveSupport::HashWithIndifferentAccess
382
+ # representation of the parameters.
372
383
  #
373
384
  # params = ActionController::Parameters.new({
374
385
  # name: "Senjougahara Hitagi",
@@ -404,11 +415,16 @@ module ActionController
404
415
  self
405
416
  end
406
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
+
407
423
  # Attribute that keeps track of converted arrays, if any, to avoid double
408
424
  # looping in the common use case permit + mass-assignment. Defined in a
409
425
  # method to instantiate it only if needed.
410
426
  #
411
- # 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
412
428
  # loop that converts values. Also, we are not going to build a new array
413
429
  # object per fetch.
414
430
  def converted_arrays
@@ -454,9 +470,9 @@ module ActionController
454
470
  # either present or the singleton +false+, returns said value:
455
471
  #
456
472
  # ActionController::Parameters.new(person: { name: "Francesco" }).require(:person)
457
- # # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
473
+ # # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
458
474
  #
459
- # Otherwise raises <tt>ActionController::ParameterMissing</tt>:
475
+ # Otherwise raises ActionController::ParameterMissing:
460
476
  #
461
477
  # ActionController::Parameters.new.require(:person)
462
478
  # # ActionController::ParameterMissing: param is missing or the value is empty: person
@@ -508,10 +524,9 @@ module ActionController
508
524
  end
509
525
  end
510
526
 
511
- # Alias of #require.
512
527
  alias :required :require
513
528
 
514
- # Returns a new <tt>ActionController::Parameters</tt> instance that
529
+ # Returns a new +ActionController::Parameters+ instance that
515
530
  # includes only the given +filters+ and sets the +permitted+ attribute
516
531
  # for the object to +true+. This is useful for limiting which attributes
517
532
  # should be allowed for mass updating.
@@ -530,7 +545,7 @@ module ActionController
530
545
  # +:name+ passes if it is a key of +params+ whose associated value is of type
531
546
  # +String+, +Symbol+, +NilClass+, +Numeric+, +TrueClass+, +FalseClass+,
532
547
  # +Date+, +Time+, +DateTime+, +StringIO+, +IO+,
533
- # +ActionDispatch::Http::UploadedFile+ or +Rack::Test::UploadedFile+.
548
+ # ActionDispatch::Http::UploadedFile or +Rack::Test::UploadedFile+.
534
549
  # Otherwise, the key +:name+ is filtered out.
535
550
  #
536
551
  # You may declare that the parameter should be an array of permitted scalars
@@ -582,13 +597,48 @@ module ActionController
582
597
  # })
583
598
  #
584
599
  # params.require(:person).permit(:contact)
585
- # # => <ActionController::Parameters {} permitted: true>
600
+ # # => #<ActionController::Parameters {} permitted: true>
586
601
  #
587
602
  # params.require(:person).permit(contact: :phone)
588
- # # => <ActionController::Parameters {"contact"=><ActionController::Parameters {"phone"=>"555-1234"} permitted: true>} permitted: true>
603
+ # # => #<ActionController::Parameters {"contact"=>#<ActionController::Parameters {"phone"=>"555-1234"} permitted: true>} permitted: true>
589
604
  #
590
605
  # params.require(:person).permit(contact: [ :email, :phone ])
591
- # # => <ActionController::Parameters {"contact"=><ActionController::Parameters {"email"=>"none@test.com", "phone"=>"555-1234"} permitted: true>} permitted: true>
606
+ # # => #<ActionController::Parameters {"contact"=>#<ActionController::Parameters {"email"=>"none@test.com", "phone"=>"555-1234"} permitted: true>} permitted: true>
607
+ #
608
+ # If your parameters specify multiple parameters indexed by a number,
609
+ # you can permit each set of parameters under the numeric key to be the same using the same syntax as permitting a single item.
610
+ #
611
+ # params = ActionController::Parameters.new({
612
+ # person: {
613
+ # '0': {
614
+ # email: "none@test.com",
615
+ # phone: "555-1234"
616
+ # },
617
+ # '1': {
618
+ # email: "nothing@test.com",
619
+ # phone: "555-6789"
620
+ # },
621
+ # }
622
+ # })
623
+ # params.permit(person: [:email]).to_h
624
+ # # => {"person"=>{"0"=>{"email"=>"none@test.com"}, "1"=>{"email"=>"nothing@test.com"}}}
625
+ #
626
+ # If you want to specify what keys you want from each numeric key, you can instead specify each one individually
627
+ #
628
+ # params = ActionController::Parameters.new({
629
+ # person: {
630
+ # '0': {
631
+ # email: "none@test.com",
632
+ # phone: "555-1234"
633
+ # },
634
+ # '1': {
635
+ # email: "nothing@test.com",
636
+ # phone: "555-6789"
637
+ # },
638
+ # }
639
+ # })
640
+ # params.permit(person: { '0': [:email], '1': [:phone]}).to_h
641
+ # # => {"person"=>{"0"=>{"email"=>"none@test.com"}, "1"=>{"phone"=>"555-6789"}}}
592
642
  def permit(*filters)
593
643
  params = self.class.new
594
644
 
@@ -610,29 +660,29 @@ module ActionController
610
660
  # returns +nil+.
611
661
  #
612
662
  # params = ActionController::Parameters.new(person: { name: "Francesco" })
613
- # params[:person] # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
663
+ # params[:person] # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
614
664
  # params[:none] # => nil
615
665
  def [](key)
616
666
  convert_hashes_to_parameters(key, @parameters[key])
617
667
  end
618
668
 
619
669
  # Assigns a value to a given +key+. The given key may still get filtered out
620
- # when +permit+ is called.
670
+ # when #permit is called.
621
671
  def []=(key, value)
622
672
  @parameters[key] = value
623
673
  end
624
674
 
625
675
  # Returns a parameter for the given +key+. If the +key+
626
676
  # can't be found, there are several options: With no other arguments,
627
- # it will raise an <tt>ActionController::ParameterMissing</tt> error;
677
+ # it will raise an ActionController::ParameterMissing error;
628
678
  # if a second argument is given, then that is returned (converted to an
629
- # instance of ActionController::Parameters if possible); if a block
679
+ # instance of +ActionController::Parameters+ if possible); if a block
630
680
  # is given, then that will be run and its result returned.
631
681
  #
632
682
  # params = ActionController::Parameters.new(person: { name: "Francesco" })
633
- # params.fetch(:person) # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
683
+ # params.fetch(:person) # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
634
684
  # params.fetch(:none) # => ActionController::ParameterMissing: param is missing or the value is empty: none
635
- # params.fetch(:none, {}) # => <ActionController::Parameters {} permitted: false>
685
+ # params.fetch(:none, {}) # => #<ActionController::Parameters {} permitted: false>
636
686
  # params.fetch(:none, "Francesco") # => "Francesco"
637
687
  # params.fetch(:none) { "Francesco" } # => "Francesco"
638
688
  def fetch(key, *args)
@@ -661,49 +711,50 @@ module ActionController
661
711
  @parameters.dig(*keys)
662
712
  end
663
713
 
664
- # Returns a new <tt>ActionController::Parameters</tt> instance that
714
+ # Returns a new +ActionController::Parameters+ instance that
665
715
  # includes only the given +keys+. If the given +keys+
666
716
  # don't exist, returns an empty hash.
667
717
  #
668
718
  # params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
669
- # params.slice(:a, :b) # => <ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
670
- # params.slice(:d) # => <ActionController::Parameters {} permitted: false>
719
+ # params.slice(:a, :b) # => #<ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
720
+ # params.slice(:d) # => #<ActionController::Parameters {} permitted: false>
671
721
  def slice(*keys)
672
722
  new_instance_with_inherited_permitted_status(@parameters.slice(*keys))
673
723
  end
674
724
 
675
- # Returns current <tt>ActionController::Parameters</tt> instance which
725
+ # Returns the current +ActionController::Parameters+ instance which
676
726
  # contains only the given +keys+.
677
727
  def slice!(*keys)
678
728
  @parameters.slice!(*keys)
679
729
  self
680
730
  end
681
731
 
682
- # Returns a new <tt>ActionController::Parameters</tt> instance that
732
+ # Returns a new +ActionController::Parameters+ instance that
683
733
  # filters out the given +keys+.
684
734
  #
685
735
  # params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
686
- # params.except(:a, :b) # => <ActionController::Parameters {"c"=>3} permitted: false>
687
- # params.except(:d) # => <ActionController::Parameters {"a"=>1, "b"=>2, "c"=>3} permitted: false>
736
+ # params.except(:a, :b) # => #<ActionController::Parameters {"c"=>3} permitted: false>
737
+ # params.except(:d) # => #<ActionController::Parameters {"a"=>1, "b"=>2, "c"=>3} permitted: false>
688
738
  def except(*keys)
689
739
  new_instance_with_inherited_permitted_status(@parameters.except(*keys))
690
740
  end
741
+ alias_method :without, :except
691
742
 
692
743
  # Removes and returns the key/value pairs matching the given keys.
693
744
  #
694
745
  # params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
695
- # params.extract!(:a, :b) # => <ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
696
- # params # => <ActionController::Parameters {"c"=>3} permitted: false>
746
+ # params.extract!(:a, :b) # => #<ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
747
+ # params # => #<ActionController::Parameters {"c"=>3} permitted: false>
697
748
  def extract!(*keys)
698
749
  new_instance_with_inherited_permitted_status(@parameters.extract!(*keys))
699
750
  end
700
751
 
701
- # Returns a new <tt>ActionController::Parameters</tt> with the results of
752
+ # Returns a new +ActionController::Parameters+ instance with the results of
702
753
  # running +block+ once for every value. The keys are unchanged.
703
754
  #
704
755
  # params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
705
756
  # params.transform_values { |x| x * 2 }
706
- # # => <ActionController::Parameters {"a"=>2, "b"=>4, "c"=>6} permitted: false>
757
+ # # => #<ActionController::Parameters {"a"=>2, "b"=>4, "c"=>6} permitted: false>
707
758
  def transform_values
708
759
  return to_enum(:transform_values) unless block_given?
709
760
  new_instance_with_inherited_permitted_status(
@@ -712,14 +763,14 @@ module ActionController
712
763
  end
713
764
 
714
765
  # Performs values transformation and returns the altered
715
- # <tt>ActionController::Parameters</tt> instance.
766
+ # +ActionController::Parameters+ instance.
716
767
  def transform_values!
717
768
  return to_enum(:transform_values!) unless block_given?
718
769
  @parameters.transform_values! { |v| yield convert_value_to_parameters(v) }
719
770
  self
720
771
  end
721
772
 
722
- # Returns a new <tt>ActionController::Parameters</tt> instance with the
773
+ # Returns a new +ActionController::Parameters+ instance with the
723
774
  # results of running +block+ once for every key. The values are unchanged.
724
775
  def transform_keys(&block)
725
776
  return to_enum(:transform_keys) unless block_given?
@@ -729,14 +780,14 @@ module ActionController
729
780
  end
730
781
 
731
782
  # Performs keys transformation and returns the altered
732
- # <tt>ActionController::Parameters</tt> instance.
783
+ # +ActionController::Parameters+ instance.
733
784
  def transform_keys!(&block)
734
785
  return to_enum(:transform_keys!) unless block_given?
735
786
  @parameters.transform_keys!(&block)
736
787
  self
737
788
  end
738
789
 
739
- # Returns a new <tt>ActionController::Parameters</tt> instance with the
790
+ # Returns a new +ActionController::Parameters+ instance with the
740
791
  # results of running +block+ once for every key. This includes the keys
741
792
  # from the root hash and from all nested hashes and arrays. The values are unchanged.
742
793
  def deep_transform_keys(&block)
@@ -745,9 +796,9 @@ module ActionController
745
796
  )
746
797
  end
747
798
 
748
- # Returns the <tt>ActionController::Parameters</tt> instance changing its keys.
749
- # This includes the keys from the root hash and from all nested hashes and arrays.
750
- # 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.
751
802
  def deep_transform_keys!(&block)
752
803
  @parameters.deep_transform_keys!(&block)
753
804
  self
@@ -755,13 +806,13 @@ module ActionController
755
806
 
756
807
  # Deletes a key-value pair from +Parameters+ and returns the value. If
757
808
  # +key+ is not found, returns +nil+ (or, with optional code block, yields
758
- # +key+ and returns the result). Cf. +#extract!+, which returns the
759
- # corresponding +ActionController::Parameters+ object.
809
+ # +key+ and returns the result). This method is similar to #extract!, which
810
+ # returns the corresponding +ActionController::Parameters+ object.
760
811
  def delete(key, &block)
761
812
  convert_value_to_parameters(@parameters.delete(key, &block))
762
813
  end
763
814
 
764
- # Returns a new instance of <tt>ActionController::Parameters</tt> with only
815
+ # Returns a new +ActionController::Parameters+ instance with only
765
816
  # items that the block evaluates to true.
766
817
  def select(&block)
767
818
  new_instance_with_inherited_permitted_status(@parameters.select(&block))
@@ -774,7 +825,7 @@ module ActionController
774
825
  end
775
826
  alias_method :keep_if, :select!
776
827
 
777
- # Returns a new instance of <tt>ActionController::Parameters</tt> with items
828
+ # Returns a new +ActionController::Parameters+ instance with items
778
829
  # that the block evaluates to true removed.
779
830
  def reject(&block)
780
831
  new_instance_with_inherited_permitted_status(@parameters.reject(&block))
@@ -787,7 +838,7 @@ module ActionController
787
838
  end
788
839
  alias_method :delete_if, :reject!
789
840
 
790
- # Returns a new instance of <tt>ActionController::Parameters</tt> with +nil+ values removed.
841
+ # Returns a new +ActionController::Parameters+ instance with +nil+ values removed.
791
842
  def compact
792
843
  new_instance_with_inherited_permitted_status(@parameters.compact)
793
844
  end
@@ -797,7 +848,7 @@ module ActionController
797
848
  self if @parameters.compact!
798
849
  end
799
850
 
800
- # Returns a new instance of <tt>ActionController::Parameters</tt> without the blank values.
851
+ # Returns a new +ActionController::Parameters+ instance without the blank values.
801
852
  # Uses Object#blank? for determining if a value is blank.
802
853
  def compact_blank
803
854
  reject { |_k, v| v.blank? }
@@ -809,13 +860,20 @@ module ActionController
809
860
  reject! { |_k, v| v.blank? }
810
861
  end
811
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
+
812
870
  # Returns values that were assigned to the given +keys+. Note that all the
813
- # +Hash+ objects will be converted to <tt>ActionController::Parameters</tt>.
871
+ # +Hash+ objects will be converted to +ActionController::Parameters+.
814
872
  def values_at(*keys)
815
873
  convert_value_to_parameters(@parameters.values_at(*keys))
816
874
  end
817
875
 
818
- # Returns a new <tt>ActionController::Parameters</tt> with all keys from
876
+ # Returns a new +ActionController::Parameters+ instance with all keys from
819
877
  # +other_hash+ merged into current hash.
820
878
  def merge(other_hash)
821
879
  new_instance_with_inherited_permitted_status(
@@ -823,15 +881,22 @@ module ActionController
823
881
  )
824
882
  end
825
883
 
826
- # Returns current <tt>ActionController::Parameters</tt> instance with
884
+ ##
885
+ # :call-seq: merge!(other_hash)
886
+ #
887
+ # Returns the current +ActionController::Parameters+ instance with
827
888
  # +other_hash+ merged into current hash.
828
- def merge!(other_hash)
829
- @parameters.merge!(other_hash.to_h)
889
+ def merge!(other_hash, &block)
890
+ @parameters.merge!(other_hash.to_h, &block)
830
891
  self
831
892
  end
832
893
 
833
- # Returns a new <tt>ActionController::Parameters</tt> with all keys from
834
- # 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+.
835
900
  def reverse_merge(other_hash)
836
901
  new_instance_with_inherited_permitted_status(
837
902
  other_hash.to_h.merge(@parameters)
@@ -839,7 +904,7 @@ module ActionController
839
904
  end
840
905
  alias_method :with_defaults, :reverse_merge
841
906
 
842
- # Returns current <tt>ActionController::Parameters</tt> instance with
907
+ # Returns the current +ActionController::Parameters+ instance with
843
908
  # current hash merged into +other_hash+.
844
909
  def reverse_merge!(other_hash)
845
910
  @parameters.merge!(other_hash.to_h) { |key, left, right| left }
@@ -885,13 +950,33 @@ module ActionController
885
950
  end
886
951
  end
887
952
 
888
- # Returns duplicate of object including all parameters.
953
+ def encode_with(coder) # :nodoc:
954
+ coder.map = { "parameters" => @parameters, "permitted" => @permitted }
955
+ end
956
+
957
+ # Returns a duplicate +ActionController::Parameters+ instance with the same permitted parameters.
889
958
  def deep_dup
890
- self.class.new(@parameters.deep_dup).tap do |duplicate|
959
+ self.class.new(@parameters.deep_dup, @logging_context).tap do |duplicate|
891
960
  duplicate.permitted = @permitted
892
961
  end
893
962
  end
894
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
+
895
980
  protected
896
981
  attr_reader :parameters
897
982
 
@@ -909,19 +994,20 @@ module ActionController
909
994
 
910
995
  private
911
996
  def new_instance_with_inherited_permitted_status(hash)
912
- self.class.new(hash).tap do |new_instance|
997
+ self.class.new(hash, @logging_context).tap do |new_instance|
913
998
  new_instance.permitted = @permitted
914
999
  end
915
1000
  end
916
1001
 
917
- def convert_parameters_to_hashes(value, using)
1002
+ def convert_parameters_to_hashes(value, using, &block)
918
1003
  case value
919
1004
  when Array
920
1005
  value.map { |v| convert_parameters_to_hashes(v, using) }
921
1006
  when Hash
922
- value.transform_values do |v|
1007
+ transformed = value.transform_values do |v|
923
1008
  convert_parameters_to_hashes(v, using)
924
- end.with_indifferent_access
1009
+ end
1010
+ (block_given? ? transformed.to_h(&block) : transformed).with_indifferent_access
925
1011
  when Parameters
926
1012
  value.send(using)
927
1013
  else
@@ -943,18 +1029,24 @@ module ActionController
943
1029
  converted_arrays << converted.dup
944
1030
  converted
945
1031
  when Hash
946
- self.class.new(value)
1032
+ self.class.new(value, @logging_context)
947
1033
  else
948
1034
  value
949
1035
  end
950
1036
  end
951
1037
 
952
- def each_element(object, &block)
1038
+ def specify_numeric_keys?(filter)
1039
+ if filter.respond_to?(:keys)
1040
+ filter.keys.any? { |key| /\A-?\d+\z/.match?(key) }
1041
+ end
1042
+ end
1043
+
1044
+ def each_element(object, filter, &block)
953
1045
  case object
954
1046
  when Array
955
- object.grep(Parameters).map { |el| yield el }.compact
1047
+ object.grep(Parameters).filter_map(&block)
956
1048
  when Parameters
957
- if object.nested_attributes?
1049
+ if object.nested_attributes? && !specify_numeric_keys?(filter)
958
1050
  object.each_nested_attribute(&block)
959
1051
  else
960
1052
  yield object
@@ -968,7 +1060,7 @@ module ActionController
968
1060
  case self.class.action_on_unpermitted_parameters
969
1061
  when :log
970
1062
  name = "unpermitted_parameters.action_controller"
971
- ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys)
1063
+ ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys, context: @logging_context)
972
1064
  when :raise
973
1065
  raise ActionController::UnpermittedParameters.new(unpermitted_keys)
974
1066
  end
@@ -986,10 +1078,11 @@ module ActionController
986
1078
  # This is a list of permitted scalar types that includes the ones
987
1079
  # supported in XML and JSON requests.
988
1080
  #
989
- # 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
990
1082
  # as first element to quickly short-circuit the common case.
991
1083
  #
992
- # 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.
993
1086
  PERMITTED_SCALAR_TYPES = [
994
1087
  String,
995
1088
  Symbol,
@@ -1045,8 +1138,8 @@ module ActionController
1045
1138
  value.is_a?(Array) || value.is_a?(Parameters)
1046
1139
  end
1047
1140
 
1048
- EMPTY_ARRAY = []
1049
- EMPTY_HASH = {}
1141
+ EMPTY_ARRAY = [] # :nodoc:
1142
+ EMPTY_HASH = {} # :nodoc:
1050
1143
  def hash_filter(params, filter)
1051
1144
  filter = filter.with_indifferent_access
1052
1145
 
@@ -1067,7 +1160,7 @@ module ActionController
1067
1160
  end
1068
1161
  elsif non_scalar?(value)
1069
1162
  # Declaration { user: :name } or { user: [:name, :age, { address: ... }] }.
1070
- params[key] = each_element(value) do |element|
1163
+ params[key] = each_element(value, filter[key]) do |element|
1071
1164
  element.permit(*Array.wrap(filter[key]))
1072
1165
  end
1073
1166
  end
@@ -1097,6 +1190,8 @@ module ActionController
1097
1190
  case element
1098
1191
  when ->(e) { permitted_scalar?(e) }
1099
1192
  sanitized << element
1193
+ when Array
1194
+ sanitized << permit_any_in_array(element)
1100
1195
  when Parameters
1101
1196
  sanitized << permit_any_in_parameters(element)
1102
1197
  else
@@ -1112,7 +1207,7 @@ module ActionController
1112
1207
  end
1113
1208
  end
1114
1209
 
1115
- # == Strong \Parameters
1210
+ # = Strong \Parameters
1116
1211
  #
1117
1212
  # It provides an interface for protecting attributes from end-user
1118
1213
  # assignment. This makes Action Controller parameters forbidden
@@ -1184,7 +1279,15 @@ module ActionController
1184
1279
  # Returns a new ActionController::Parameters object that
1185
1280
  # has been instantiated with the <tt>request.parameters</tt>.
1186
1281
  def params
1187
- @_params ||= Parameters.new(request.parameters)
1282
+ @_params ||= begin
1283
+ context = {
1284
+ controller: self.class.name,
1285
+ action: action_name,
1286
+ request: request,
1287
+ params: request.filtered_parameters
1288
+ }
1289
+ Parameters.new(request.parameters, context)
1290
+ end
1188
1291
  end
1189
1292
 
1190
1293
  # Assigns the given +value+ to the +params+ hash. If +value+