actionpack 7.0.8.6 → 7.1.0.beta1

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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +318 -423
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/abstract_controller/base.rb +19 -10
  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 +61 -18
  10. data/lib/abstract_controller/railties/routes_helpers.rb +1 -16
  11. data/lib/abstract_controller/rendering.rb +3 -3
  12. data/lib/abstract_controller/translation.rb +1 -27
  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 +5 -3
  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/content_security_policy.rb +1 -1
  22. data/lib/action_controller/metal/data_streaming.rb +2 -0
  23. data/lib/action_controller/metal/default_headers.rb +2 -0
  24. data/lib/action_controller/metal/etag_with_flash.rb +2 -0
  25. data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
  26. data/lib/action_controller/metal/exceptions.rb +8 -0
  27. data/lib/action_controller/metal/head.rb +8 -6
  28. data/lib/action_controller/metal/helpers.rb +3 -14
  29. data/lib/action_controller/metal/http_authentication.rb +10 -4
  30. data/lib/action_controller/metal/implicit_render.rb +5 -3
  31. data/lib/action_controller/metal/instrumentation.rb +8 -1
  32. data/lib/action_controller/metal/live.rb +24 -0
  33. data/lib/action_controller/metal/mime_responds.rb +2 -2
  34. data/lib/action_controller/metal/params_wrapper.rb +3 -1
  35. data/lib/action_controller/metal/permissions_policy.rb +1 -1
  36. data/lib/action_controller/metal/redirecting.rb +6 -6
  37. data/lib/action_controller/metal/renderers.rb +2 -2
  38. data/lib/action_controller/metal/rendering.rb +0 -7
  39. data/lib/action_controller/metal/request_forgery_protection.rb +138 -50
  40. data/lib/action_controller/metal/rescue.rb +2 -0
  41. data/lib/action_controller/metal/streaming.rb +70 -30
  42. data/lib/action_controller/metal/strong_parameters.rb +89 -50
  43. data/lib/action_controller/metal/url_for.rb +7 -0
  44. data/lib/action_controller/metal.rb +79 -21
  45. data/lib/action_controller/railtie.rb +22 -9
  46. data/lib/action_controller/renderer.rb +98 -65
  47. data/lib/action_controller/test_case.rb +15 -5
  48. data/lib/action_controller.rb +8 -1
  49. data/lib/action_dispatch/constants.rb +32 -0
  50. data/lib/action_dispatch/deprecator.rb +7 -0
  51. data/lib/action_dispatch/http/cache.rb +1 -3
  52. data/lib/action_dispatch/http/content_security_policy.rb +9 -8
  53. data/lib/action_dispatch/http/filter_parameters.rb +15 -14
  54. data/lib/action_dispatch/http/headers.rb +2 -0
  55. data/lib/action_dispatch/http/mime_negotiation.rb +21 -21
  56. data/lib/action_dispatch/http/mime_type.rb +35 -12
  57. data/lib/action_dispatch/http/mime_types.rb +3 -1
  58. data/lib/action_dispatch/http/parameters.rb +1 -1
  59. data/lib/action_dispatch/http/permissions_policy.rb +44 -15
  60. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  61. data/lib/action_dispatch/http/request.rb +48 -14
  62. data/lib/action_dispatch/http/response.rb +78 -59
  63. data/lib/action_dispatch/http/upload.rb +2 -0
  64. data/lib/action_dispatch/journey/formatter.rb +8 -2
  65. data/lib/action_dispatch/journey/path/pattern.rb +14 -14
  66. data/lib/action_dispatch/journey/route.rb +3 -2
  67. data/lib/action_dispatch/journey/router.rb +5 -4
  68. data/lib/action_dispatch/journey/routes.rb +2 -2
  69. data/lib/action_dispatch/log_subscriber.rb +23 -0
  70. data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -6
  71. data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
  72. data/lib/action_dispatch/middleware/callbacks.rb +2 -0
  73. data/lib/action_dispatch/middleware/cookies.rb +81 -98
  74. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -25
  75. data/lib/action_dispatch/middleware/debug_locks.rb +4 -1
  76. data/lib/action_dispatch/middleware/debug_view.rb +7 -2
  77. data/lib/action_dispatch/middleware/exception_wrapper.rb +181 -27
  78. data/lib/action_dispatch/middleware/executor.rb +1 -1
  79. data/lib/action_dispatch/middleware/flash.rb +7 -0
  80. data/lib/action_dispatch/middleware/host_authorization.rb +6 -3
  81. data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
  82. data/lib/action_dispatch/middleware/reloader.rb +7 -5
  83. data/lib/action_dispatch/middleware/remote_ip.rb +17 -16
  84. data/lib/action_dispatch/middleware/request_id.rb +2 -0
  85. data/lib/action_dispatch/middleware/server_timing.rb +4 -4
  86. data/lib/action_dispatch/middleware/session/abstract_store.rb +5 -0
  87. data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
  88. data/lib/action_dispatch/middleware/session/cookie_store.rb +11 -5
  89. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
  90. data/lib/action_dispatch/middleware/show_exceptions.rb +19 -15
  91. data/lib/action_dispatch/middleware/ssl.rb +18 -6
  92. data/lib/action_dispatch/middleware/stack.rb +7 -2
  93. data/lib/action_dispatch/middleware/static.rb +12 -8
  94. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
  95. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +4 -4
  96. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
  97. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +7 -7
  98. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
  99. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +17 -0
  100. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +16 -12
  101. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -1
  102. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
  103. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +4 -4
  104. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  105. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
  106. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
  107. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +46 -37
  108. data/lib/action_dispatch/railtie.rb +14 -4
  109. data/lib/action_dispatch/request/session.rb +16 -6
  110. data/lib/action_dispatch/request/utils.rb +8 -3
  111. data/lib/action_dispatch/routing/inspector.rb +54 -6
  112. data/lib/action_dispatch/routing/mapper.rb +26 -14
  113. data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
  114. data/lib/action_dispatch/routing/redirection.rb +15 -6
  115. data/lib/action_dispatch/routing/route_set.rb +52 -22
  116. data/lib/action_dispatch/routing/routes_proxy.rb +1 -1
  117. data/lib/action_dispatch/routing/url_for.rb +5 -1
  118. data/lib/action_dispatch/routing.rb +4 -4
  119. data/lib/action_dispatch/system_test_case.rb +3 -3
  120. data/lib/action_dispatch/system_testing/browser.rb +5 -6
  121. data/lib/action_dispatch/system_testing/driver.rb +13 -21
  122. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +27 -16
  123. data/lib/action_dispatch/testing/assertions/response.rb +13 -6
  124. data/lib/action_dispatch/testing/assertions/routing.rb +67 -28
  125. data/lib/action_dispatch/testing/assertions.rb +3 -1
  126. data/lib/action_dispatch/testing/integration.rb +27 -17
  127. data/lib/action_dispatch/testing/request_encoder.rb +4 -1
  128. data/lib/action_dispatch/testing/test_process.rb +4 -3
  129. data/lib/action_dispatch/testing/test_request.rb +1 -1
  130. data/lib/action_dispatch/testing/test_response.rb +23 -9
  131. data/lib/action_dispatch.rb +37 -4
  132. data/lib/action_pack/gem_version.rb +4 -4
  133. data/lib/action_pack/version.rb +1 -1
  134. data/lib/action_pack.rb +1 -1
  135. metadata +55 -33
@@ -1,30 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rack/chunked"
4
-
5
3
  module ActionController # :nodoc:
4
+ # = Action Controller \Streaming
5
+ #
6
6
  # Allows views to be streamed back to the client as they are rendered.
7
7
  #
8
- # By default, Rails renders views by first rendering the template
8
+ # By default, \Rails renders views by first rendering the template
9
9
  # and then the layout. The response is sent to the client after the whole
10
10
  # template is rendered, all queries are made, and the layout is processed.
11
11
  #
12
- # Streaming inverts the rendering flow by rendering the layout first and
13
- # streaming each part of the layout as they are processed. This allows the
12
+ # \Streaming inverts the rendering flow by rendering the layout first and
13
+ # subsequently each part of the layout as they are processed. This allows the
14
14
  # header of the HTML (which is usually in the layout) to be streamed back
15
- # to client very quickly, allowing JavaScripts and stylesheets to be loaded
15
+ # to client very quickly, enabling JavaScripts and stylesheets to be loaded
16
16
  # earlier than usual.
17
17
  #
18
- # This approach was introduced in Rails 3.1 and is still improving. Several
19
- # Rack middlewares may not work and you need to be careful when streaming.
20
- # Those points are going to be addressed soon.
21
- #
22
- # In order to use streaming, you will need to use a Ruby version that
23
- # supports fibers (fibers are supported since version 1.9.2 of the main
24
- # Ruby implementation).
18
+ # Several Rack middlewares may not work and you need to be careful when streaming.
19
+ # This is covered in more detail below, see the Streaming@Middlewares section.
25
20
  #
26
- # Streaming can be added to a given template easily, all you need to do is
27
- # to pass the +:stream+ option.
21
+ # \Streaming can be added to a given template easily, all you need to do is
22
+ # to pass the +:stream+ option to +render+.
28
23
  #
29
24
  # class PostsController
30
25
  # def index
@@ -35,7 +30,7 @@ module ActionController # :nodoc:
35
30
  #
36
31
  # == When to use streaming
37
32
  #
38
- # Streaming may be considered to be overkill for lightweight actions like
33
+ # \Streaming may be considered to be overkill for lightweight actions like
39
34
  # +new+ or +edit+. The real benefit of streaming is on expensive actions
40
35
  # that, for example, do a lot of queries on the database.
41
36
  #
@@ -59,13 +54,13 @@ module ActionController # :nodoc:
59
54
  # render stream: true
60
55
  # end
61
56
  #
62
- # Notice that +:stream+ only works with templates. Rendering +:json+
57
+ # Notice that +:stream+ only works with templates. \Rendering +:json+
63
58
  # or +:xml+ with +:stream+ won't work.
64
59
  #
65
60
  # == Communication between layout and template
66
61
  #
67
62
  # When streaming, rendering happens top-down instead of inside-out.
68
- # Rails starts with the layout, and the template is rendered later,
63
+ # \Rails starts with the layout, and the template is rendered later,
69
64
  # when its +yield+ is reached.
70
65
  #
71
66
  # This means that, if your application currently relies on instance
@@ -112,7 +107,7 @@ module ActionController # :nodoc:
112
107
  # This means that, if you have <code>yield :title</code> in your layout
113
108
  # and you want to use streaming, you would have to render the whole template
114
109
  # (and eventually trigger all queries) before streaming the title and all
115
- # assets, which kills the purpose of streaming. For this purpose, you can use
110
+ # assets, which defeats the purpose of streaming. Alternatively, you can use
116
111
  # a helper called +provide+ that does the same as +content_for+ but tells the
117
112
  # layout to stop searching for other entries and continue rendering.
118
113
  #
@@ -122,7 +117,7 @@ module ActionController # :nodoc:
122
117
  # Hello
123
118
  # <%= content_for :title, " page" %>
124
119
  #
125
- # Giving:
120
+ # Resulting in:
126
121
  #
127
122
  # <html>
128
123
  # <head><title>Main</title></head>
@@ -132,6 +127,8 @@ module ActionController # :nodoc:
132
127
  # That said, when streaming, you need to properly check your templates
133
128
  # and choose when to use +provide+ and +content_for+.
134
129
  #
130
+ # See also ActionView::Helpers::CaptureHelper for more information.
131
+ #
135
132
  # == Headers, cookies, session, and flash
136
133
  #
137
134
  # When streaming, the HTTP headers are sent to the client right before
@@ -143,10 +140,10 @@ module ActionController # :nodoc:
143
140
  #
144
141
  # Middlewares that need to manipulate the body won't work with streaming.
145
142
  # You should disable those middlewares whenever streaming in development
146
- # or production. For instance, <tt>Rack::Bug</tt> won't work when streaming as it
143
+ # or production. For instance, +Rack::Bug+ won't work when streaming as it
147
144
  # needs to inject contents in the HTML body.
148
145
  #
149
- # Also <tt>Rack::Cache</tt> won't work with streaming as it does not support
146
+ # Also +Rack::Cache+ won't work with streaming as it does not support
150
147
  # streaming bodies yet. Whenever streaming +Cache-Control+ is automatically
151
148
  # set to "no-cache".
152
149
  #
@@ -156,14 +153,14 @@ module ActionController # :nodoc:
156
153
  # happens because part of the template was already rendered and streamed to
157
154
  # the client, making it impossible to render a whole exception page.
158
155
  #
159
- # Currently, when an exception happens in development or production, Rails
156
+ # Currently, when an exception happens in development or production, \Rails
160
157
  # will automatically stream to the client:
161
158
  #
162
159
  # "><script>window.location = "/500.html"</script></html>
163
160
  #
164
- # The first two characters (">) are required in case the exception happens
165
- # while rendering attributes for a given tag. You can check the real cause
166
- # for the exception in your logger.
161
+ # The first two characters (<tt>"></tt>) are required in case the exception
162
+ # happens while rendering attributes for a given tag. You can check the real
163
+ # cause for the exception in your logger.
167
164
  #
168
165
  # == Web server support
169
166
  #
@@ -183,16 +180,59 @@ module ActionController # :nodoc:
183
180
  # unicorn_rails --config-file unicorn.config.rb
184
181
  #
185
182
  # You may also want to configure other parameters like <tt>:tcp_nodelay</tt>.
186
- # Please check its documentation for more information: https://bogomips.org/unicorn/Unicorn/Configurator.html#method-i-listen
183
+ #
184
+ # For more information, please check the
185
+ # {documentation}[https://bogomips.org/unicorn/Unicorn/Configurator.html#method-i-listen].
187
186
  #
188
187
  # If you are using Unicorn with NGINX, you may need to tweak NGINX.
189
- # Streaming should work out of the box on Rainbows.
188
+ # \Streaming should work out of the box on Rainbows.
190
189
  #
191
190
  # ==== Passenger
192
191
  #
193
- # To be described.
192
+ # Phusion Passenger with NGINX, offers two streaming mechanisms out of the box.
193
+ #
194
+ # 1. NGINX response buffering mechanism which is dependent on the value of
195
+ # +passenger_buffer_response+ option (default is "off").
196
+ # 2. Passenger buffering system which is always 'on' irrespective of the value
197
+ # of +passenger_buffer_response+.
198
+ #
199
+ # When +passenger_buffer_response+ is turned "on", then streaming would be
200
+ # done at the NGINX level which waits until the application is done sending
201
+ # the response back to the client.
202
+ #
203
+ # For more information, please check the
204
+ # {documentation}[https://www.phusionpassenger.com/docs/references/config_reference/nginx/#passenger_buffer_response].
194
205
  #
195
206
  module Streaming
207
+ class Body # :nodoc:
208
+ TERM = "\r\n"
209
+ TAIL = "0#{TERM}"
210
+
211
+ # Store the response body to be chunked.
212
+ def initialize(body)
213
+ @body = body
214
+ end
215
+
216
+ # For each element yielded by the response body, yield
217
+ # the element in chunked encoding.
218
+ def each(&block)
219
+ term = TERM
220
+ @body.each do |chunk|
221
+ size = chunk.bytesize
222
+ next if size == 0
223
+
224
+ yield [size.to_s(16), term, chunk.b, term].join
225
+ end
226
+ yield TAIL
227
+ yield term
228
+ end
229
+
230
+ # Close the response body if the response body supports it.
231
+ def close
232
+ @body.close if @body.respond_to?(:close)
233
+ end
234
+ end
235
+
196
236
  private
197
237
  # Set proper cache control and transfer encoding when streaming
198
238
  def _process_options(options)
@@ -211,7 +251,7 @@ module ActionController # :nodoc:
211
251
  # Call render_body if we are streaming instead of usual +render+.
212
252
  def _render_template(options)
213
253
  if options.delete(:stream)
214
- Rack::Chunked::Body.new view_renderer.render_body(view_context, options)
254
+ Body.new view_renderer.render_body(view_context, options)
215
255
  else
216
256
  super
217
257
  end
@@ -64,7 +64,14 @@ module ActionController
64
64
  end
65
65
  end
66
66
 
67
- # == Action Controller \Parameters
67
+ # Raised when initializing Parameters with keys that aren't strings or symbols.
68
+ #
69
+ # ActionController::Parameters.new(123 => 456)
70
+ # # => ActionController::InvalidParameterKey: all keys must be Strings or Symbols, got: Integer
71
+ class InvalidParameterKey < ArgumentError
72
+ end
73
+
74
+ # = Action Controller \Parameters
68
75
  #
69
76
  # Allows you to choose which attributes should be permitted for mass updating
70
77
  # and thus prevent accidentally exposing that which shouldn't be exposed.
@@ -92,8 +99,8 @@ module ActionController
92
99
  # * +permit_all_parameters+ - If it's +true+, all the parameters will be
93
100
  # permitted by default. The default is +false+.
94
101
  # * +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:
102
+ # permitted are found. The default value is <tt>:log</tt> in test and development environments,
103
+ # +false+ otherwise. The values can be:
97
104
  # * +false+ to take no action.
98
105
  # * <tt>:log</tt> to emit an <tt>ActiveSupport::Notifications.instrument</tt> event on the
99
106
  # <tt>unpermitted_parameters.action_controller</tt> topic and log at the DEBUG level.
@@ -123,7 +130,7 @@ module ActionController
123
130
  # environment they should only be set once at boot-time and never mutated at
124
131
  # runtime.
125
132
  #
126
- # You can fetch values of <tt>ActionController::Parameters</tt> using either
133
+ # You can fetch values of +ActionController::Parameters+ using either
127
134
  # <tt>:key</tt> or <tt>"key"</tt>.
128
135
  #
129
136
  # params = ActionController::Parameters.new(key: "value")
@@ -160,12 +167,12 @@ module ActionController
160
167
  # Returns true if the parameters have no key/value pairs.
161
168
 
162
169
  ##
163
- # :method: has_value?
170
+ # :method: exclude?
164
171
  #
165
172
  # :call-seq:
166
- # has_value?(value)
173
+ # exclude?(key)
167
174
  #
168
- # Returns true if the given value is present for some key in the parameters.
175
+ # Returns true if the given key is not present in the parameters.
169
176
 
170
177
  ##
171
178
  # :method: include?
@@ -191,22 +198,7 @@ module ActionController
191
198
  #
192
199
  # Returns the content of the parameters as a string.
193
200
 
194
- ##
195
- # :method: value?
196
- #
197
- # :call-seq:
198
- # value?(value)
199
- #
200
- # Returns true if the given value is present for some key in the parameters.
201
-
202
- ##
203
- # :method: values
204
- #
205
- # :call-seq:
206
- # values()
207
- #
208
- # Returns a new array of the values of the parameters.
209
- delegate :keys, :values, :has_value?, :value?, :empty?, :include?,
201
+ delegate :keys, :empty?, :exclude?, :include?,
210
202
  :as_json, :to_s, :each_key, to: :@parameters
211
203
 
212
204
  alias_method :has_key?, :include?
@@ -222,13 +214,15 @@ module ActionController
222
214
  # config.action_controller.always_permitted_parameters = %w( controller action format )
223
215
  cattr_accessor :always_permitted_parameters, default: %w( controller action )
224
216
 
217
+ cattr_accessor :allow_deprecated_parameters_hash_equality, default: true, instance_accessor: false
218
+
225
219
  class << self
226
220
  def nested_attribute?(key, value) # :nodoc:
227
221
  /\A-?\d+\z/.match?(key) && (value.is_a?(Hash) || value.is_a?(Parameters))
228
222
  end
229
223
  end
230
224
 
231
- # Returns a new <tt>ActionController::Parameters</tt> instance.
225
+ # Returns a new +ActionController::Parameters+ instance.
232
226
  # Also, sets the +permitted+ attribute to the default value of
233
227
  # <tt>ActionController::Parameters.permit_all_parameters</tt>.
234
228
  #
@@ -245,6 +239,12 @@ module ActionController
245
239
  # params.permitted? # => true
246
240
  # Person.new(params) # => #<Person id: nil, name: "Francesco">
247
241
  def initialize(parameters = {}, logging_context = {})
242
+ parameters.each_key do |key|
243
+ unless key.is_a?(String) || key.is_a?(Symbol)
244
+ raise InvalidParameterKey, "all keys must be Strings or Symbols, got: #{key.class}"
245
+ end
246
+ end
247
+
248
248
  @parameters = parameters.with_indifferent_access
249
249
  @logging_context = logging_context
250
250
  @permitted = self.class.permit_all_parameters
@@ -256,7 +256,20 @@ module ActionController
256
256
  if other.respond_to?(:permitted?)
257
257
  permitted? == other.permitted? && parameters == other.parameters
258
258
  else
259
- @parameters == other
259
+ if self.class.allow_deprecated_parameters_hash_equality && Hash === other
260
+ ActionController.deprecator.warn <<-WARNING.squish
261
+ Comparing equality between `ActionController::Parameters` and a
262
+ `Hash` is deprecated and will be removed in Rails 7.2. Please only do
263
+ comparisons between instances of `ActionController::Parameters`. If
264
+ you need to compare to a hash, first convert it using
265
+ `ActionController::Parameters#new`.
266
+ To disable the deprecated behavior set
267
+ `Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false`.
268
+ WARNING
269
+ @parameters == other
270
+ else
271
+ super
272
+ end
260
273
  end
261
274
  end
262
275
 
@@ -282,9 +295,9 @@ module ActionController
282
295
  #
283
296
  # safe_params = params.permit(:name)
284
297
  # safe_params.to_h # => {"name"=>"Senjougahara Hitagi"}
285
- def to_h
298
+ def to_h(&block)
286
299
  if permitted?
287
- convert_parameters_to_hashes(@parameters, :to_h)
300
+ convert_parameters_to_hashes(@parameters, :to_h, &block)
288
301
  else
289
302
  raise UnfilteredParameters
290
303
  end
@@ -374,6 +387,11 @@ module ActionController
374
387
  self
375
388
  end
376
389
 
390
+ # Returns a new array of the values of the parameters.
391
+ def values
392
+ to_enum(:each_value).to_a
393
+ end
394
+
377
395
  # Attribute that keeps track of converted arrays, if any, to avoid double
378
396
  # looping in the common use case permit + mass-assignment. Defined in a
379
397
  # method to instantiate it only if needed.
@@ -480,7 +498,7 @@ module ActionController
480
498
 
481
499
  alias :required :require
482
500
 
483
- # Returns a new <tt>ActionController::Parameters</tt> instance that
501
+ # Returns a new +ActionController::Parameters+ instance that
484
502
  # includes only the given +filters+ and sets the +permitted+ attribute
485
503
  # for the object to +true+. This is useful for limiting which attributes
486
504
  # should be allowed for mass updating.
@@ -665,7 +683,7 @@ module ActionController
665
683
  @parameters.dig(*keys)
666
684
  end
667
685
 
668
- # Returns a new <tt>ActionController::Parameters</tt> instance that
686
+ # Returns a new +ActionController::Parameters+ instance that
669
687
  # includes only the given +keys+. If the given +keys+
670
688
  # don't exist, returns an empty hash.
671
689
  #
@@ -676,14 +694,14 @@ module ActionController
676
694
  new_instance_with_inherited_permitted_status(@parameters.slice(*keys))
677
695
  end
678
696
 
679
- # Returns the current <tt>ActionController::Parameters</tt> instance which
697
+ # Returns the current +ActionController::Parameters+ instance which
680
698
  # contains only the given +keys+.
681
699
  def slice!(*keys)
682
700
  @parameters.slice!(*keys)
683
701
  self
684
702
  end
685
703
 
686
- # Returns a new <tt>ActionController::Parameters</tt> instance that
704
+ # Returns a new +ActionController::Parameters+ instance that
687
705
  # filters out the given +keys+.
688
706
  #
689
707
  # params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
@@ -692,6 +710,7 @@ module ActionController
692
710
  def except(*keys)
693
711
  new_instance_with_inherited_permitted_status(@parameters.except(*keys))
694
712
  end
713
+ alias_method :without, :except
695
714
 
696
715
  # Removes and returns the key/value pairs matching the given keys.
697
716
  #
@@ -702,7 +721,7 @@ module ActionController
702
721
  new_instance_with_inherited_permitted_status(@parameters.extract!(*keys))
703
722
  end
704
723
 
705
- # Returns a new <tt>ActionController::Parameters</tt> instance with the results of
724
+ # Returns a new +ActionController::Parameters+ instance with the results of
706
725
  # running +block+ once for every value. The keys are unchanged.
707
726
  #
708
727
  # params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
@@ -716,14 +735,14 @@ module ActionController
716
735
  end
717
736
 
718
737
  # Performs values transformation and returns the altered
719
- # <tt>ActionController::Parameters</tt> instance.
738
+ # +ActionController::Parameters+ instance.
720
739
  def transform_values!
721
740
  return to_enum(:transform_values!) unless block_given?
722
741
  @parameters.transform_values! { |v| yield convert_value_to_parameters(v) }
723
742
  self
724
743
  end
725
744
 
726
- # Returns a new <tt>ActionController::Parameters</tt> instance with the
745
+ # Returns a new +ActionController::Parameters+ instance with the
727
746
  # results of running +block+ once for every key. The values are unchanged.
728
747
  def transform_keys(&block)
729
748
  return to_enum(:transform_keys) unless block_given?
@@ -733,14 +752,14 @@ module ActionController
733
752
  end
734
753
 
735
754
  # Performs keys transformation and returns the altered
736
- # <tt>ActionController::Parameters</tt> instance.
755
+ # +ActionController::Parameters+ instance.
737
756
  def transform_keys!(&block)
738
757
  return to_enum(:transform_keys!) unless block_given?
739
758
  @parameters.transform_keys!(&block)
740
759
  self
741
760
  end
742
761
 
743
- # Returns a new <tt>ActionController::Parameters</tt> instance with the
762
+ # Returns a new +ActionController::Parameters+ instance with the
744
763
  # results of running +block+ once for every key. This includes the keys
745
764
  # from the root hash and from all nested hashes and arrays. The values are unchanged.
746
765
  def deep_transform_keys(&block)
@@ -749,7 +768,7 @@ module ActionController
749
768
  )
750
769
  end
751
770
 
752
- # Returns the same <tt>ActionController::Parameters</tt> instance with
771
+ # Returns the same +ActionController::Parameters+ instance with
753
772
  # changed keys. This includes the keys from the root hash and from all
754
773
  # nested hashes and arrays. The values are unchanged.
755
774
  def deep_transform_keys!(&block)
@@ -765,7 +784,7 @@ module ActionController
765
784
  convert_value_to_parameters(@parameters.delete(key, &block))
766
785
  end
767
786
 
768
- # Returns a new <tt>ActionController::Parameters</tt> instance with only
787
+ # Returns a new +ActionController::Parameters+ instance with only
769
788
  # items that the block evaluates to true.
770
789
  def select(&block)
771
790
  new_instance_with_inherited_permitted_status(@parameters.select(&block))
@@ -778,7 +797,7 @@ module ActionController
778
797
  end
779
798
  alias_method :keep_if, :select!
780
799
 
781
- # Returns a new <tt>ActionController::Parameters</tt> instance with items
800
+ # Returns a new +ActionController::Parameters+ instance with items
782
801
  # that the block evaluates to true removed.
783
802
  def reject(&block)
784
803
  new_instance_with_inherited_permitted_status(@parameters.reject(&block))
@@ -791,7 +810,7 @@ module ActionController
791
810
  end
792
811
  alias_method :delete_if, :reject!
793
812
 
794
- # Returns a new <tt>ActionController::Parameters</tt> instance with +nil+ values removed.
813
+ # Returns a new +ActionController::Parameters+ instance with +nil+ values removed.
795
814
  def compact
796
815
  new_instance_with_inherited_permitted_status(@parameters.compact)
797
816
  end
@@ -801,7 +820,7 @@ module ActionController
801
820
  self if @parameters.compact!
802
821
  end
803
822
 
804
- # Returns a new <tt>ActionController::Parameters</tt> instance without the blank values.
823
+ # Returns a new +ActionController::Parameters+ instance without the blank values.
805
824
  # Uses Object#blank? for determining if a value is blank.
806
825
  def compact_blank
807
826
  reject { |_k, v| v.blank? }
@@ -813,13 +832,20 @@ module ActionController
813
832
  reject! { |_k, v| v.blank? }
814
833
  end
815
834
 
835
+ # Returns true if the given value is present for some key in the parameters.
836
+ def has_value?(value)
837
+ each_value.include?(convert_value_to_parameters(value))
838
+ end
839
+
840
+ alias value? has_value?
841
+
816
842
  # Returns values that were assigned to the given +keys+. Note that all the
817
- # +Hash+ objects will be converted to <tt>ActionController::Parameters</tt>.
843
+ # +Hash+ objects will be converted to +ActionController::Parameters+.
818
844
  def values_at(*keys)
819
845
  convert_value_to_parameters(@parameters.values_at(*keys))
820
846
  end
821
847
 
822
- # Returns a new <tt>ActionController::Parameters</tt> instance with all keys from
848
+ # Returns a new +ActionController::Parameters+ instance with all keys from
823
849
  # +other_hash+ merged into current hash.
824
850
  def merge(other_hash)
825
851
  new_instance_with_inherited_permitted_status(
@@ -827,14 +853,14 @@ module ActionController
827
853
  )
828
854
  end
829
855
 
830
- # Returns the current <tt>ActionController::Parameters</tt> instance with
856
+ # Returns the current +ActionController::Parameters+ instance with
831
857
  # +other_hash+ merged into current hash.
832
858
  def merge!(other_hash)
833
859
  @parameters.merge!(other_hash.to_h)
834
860
  self
835
861
  end
836
862
 
837
- # Returns a new <tt>ActionController::Parameters</tt> instance with all keys
863
+ # Returns a new +ActionController::Parameters+ instance with all keys
838
864
  # from current hash merged into +other_hash+.
839
865
  def reverse_merge(other_hash)
840
866
  new_instance_with_inherited_permitted_status(
@@ -843,7 +869,7 @@ module ActionController
843
869
  end
844
870
  alias_method :with_defaults, :reverse_merge
845
871
 
846
- # Returns the current <tt>ActionController::Parameters</tt> instance with
872
+ # Returns the current +ActionController::Parameters+ instance with
847
873
  # current hash merged into +other_hash+.
848
874
  def reverse_merge!(other_hash)
849
875
  @parameters.merge!(other_hash.to_h) { |key, left, right| left }
@@ -900,6 +926,16 @@ module ActionController
900
926
  end
901
927
  end
902
928
 
929
+ # Returns parameter value for the given +key+ separated by +delimiter+.
930
+ #
931
+ # params = ActionController::Parameters.new(id: "1_123", tags: "ruby,rails")
932
+ # params.extract_value(:id) # => ["1", "123"]
933
+ # params.extract_value(:tags, delimiter: ",") # => ["ruby", "rails"]
934
+ # params.extract_value(:non_existent_key) # => nil
935
+ def extract_value(key, delimiter: "_")
936
+ @parameters[key]&.split(delimiter)
937
+ end
938
+
903
939
  protected
904
940
  attr_reader :parameters
905
941
 
@@ -922,14 +958,15 @@ module ActionController
922
958
  end
923
959
  end
924
960
 
925
- def convert_parameters_to_hashes(value, using)
961
+ def convert_parameters_to_hashes(value, using, &block)
926
962
  case value
927
963
  when Array
928
964
  value.map { |v| convert_parameters_to_hashes(v, using) }
929
965
  when Hash
930
- value.transform_values do |v|
966
+ transformed = value.transform_values do |v|
931
967
  convert_parameters_to_hashes(v, using)
932
- end.with_indifferent_access
968
+ end
969
+ (block_given? ? transformed.to_h(&block) : transformed).with_indifferent_access
933
970
  when Parameters
934
971
  value.send(using)
935
972
  else
@@ -1112,6 +1149,8 @@ module ActionController
1112
1149
  case element
1113
1150
  when ->(e) { permitted_scalar?(e) }
1114
1151
  sanitized << element
1152
+ when Array
1153
+ sanitized << permit_any_in_array(element)
1115
1154
  when Parameters
1116
1155
  sanitized << permit_any_in_parameters(element)
1117
1156
  else
@@ -1127,7 +1166,7 @@ module ActionController
1127
1166
  end
1128
1167
  end
1129
1168
 
1130
- # == Strong \Parameters
1169
+ # = Strong \Parameters
1131
1170
  #
1132
1171
  # It provides an interface for protecting attributes from end-user
1133
1172
  # assignment. This makes Action Controller parameters forbidden
@@ -1,6 +1,8 @@
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
  #
@@ -25,6 +27,11 @@ module ActionController
25
27
 
26
28
  include AbstractController::UrlFor
27
29
 
30
+ def initialize(...)
31
+ super
32
+ @_url_options = nil
33
+ end
34
+
28
35
  def url_options
29
36
  @_url_options ||= {
30
37
  host: request.host,