actionpack 5.2.6 → 6.1.4.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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +327 -335
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/abstract_controller/base.rb +38 -4
  6. data/lib/abstract_controller/caching/fragments.rb +6 -22
  7. data/lib/abstract_controller/caching.rb +1 -1
  8. data/lib/abstract_controller/callbacks.rb +14 -2
  9. data/lib/abstract_controller/collector.rb +1 -2
  10. data/lib/abstract_controller/helpers.rb +106 -90
  11. data/lib/abstract_controller/railties/routes_helpers.rb +17 -1
  12. data/lib/abstract_controller/rendering.rb +9 -9
  13. data/lib/abstract_controller/translation.rb +11 -5
  14. data/lib/abstract_controller.rb +1 -0
  15. data/lib/action_controller/api.rb +4 -3
  16. data/lib/action_controller/base.rb +6 -9
  17. data/lib/action_controller/caching.rb +1 -3
  18. data/lib/action_controller/log_subscriber.rb +10 -7
  19. data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
  20. data/lib/action_controller/metal/conditional_get.rb +19 -5
  21. data/lib/action_controller/metal/content_security_policy.rb +1 -2
  22. data/lib/action_controller/metal/cookies.rb +3 -1
  23. data/lib/action_controller/metal/data_streaming.rb +6 -7
  24. data/lib/action_controller/metal/default_headers.rb +17 -0
  25. data/lib/action_controller/metal/etag_with_template_digest.rb +4 -6
  26. data/lib/action_controller/metal/exceptions.rb +56 -2
  27. data/lib/action_controller/metal/flash.rb +5 -5
  28. data/lib/action_controller/metal/head.rb +7 -4
  29. data/lib/action_controller/metal/helpers.rb +14 -5
  30. data/lib/action_controller/metal/http_authentication.rb +24 -23
  31. data/lib/action_controller/metal/implicit_render.rb +5 -15
  32. data/lib/action_controller/metal/instrumentation.rb +13 -14
  33. data/lib/action_controller/metal/live.rb +39 -32
  34. data/lib/action_controller/metal/logging.rb +20 -0
  35. data/lib/action_controller/metal/mime_responds.rb +19 -4
  36. data/lib/action_controller/metal/parameter_encoding.rb +35 -4
  37. data/lib/action_controller/metal/params_wrapper.rb +32 -22
  38. data/lib/action_controller/metal/permissions_policy.rb +46 -0
  39. data/lib/action_controller/metal/redirecting.rb +6 -6
  40. data/lib/action_controller/metal/renderers.rb +4 -4
  41. data/lib/action_controller/metal/rendering.rb +8 -3
  42. data/lib/action_controller/metal/request_forgery_protection.rb +26 -49
  43. data/lib/action_controller/metal/rescue.rb +1 -1
  44. data/lib/action_controller/metal/streaming.rb +0 -1
  45. data/lib/action_controller/metal/strong_parameters.rb +167 -58
  46. data/lib/action_controller/metal/url_for.rb +1 -1
  47. data/lib/action_controller/metal.rb +10 -8
  48. data/lib/action_controller/railties/helpers.rb +1 -1
  49. data/lib/action_controller/renderer.rb +37 -13
  50. data/lib/action_controller/template_assertions.rb +1 -1
  51. data/lib/action_controller/test_case.rb +71 -63
  52. data/lib/action_controller.rb +7 -4
  53. data/lib/action_dispatch/http/cache.rb +31 -27
  54. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  55. data/lib/action_dispatch/http/content_security_policy.rb +33 -19
  56. data/lib/action_dispatch/http/filter_parameters.rb +9 -8
  57. data/lib/action_dispatch/http/filter_redirect.rb +2 -3
  58. data/lib/action_dispatch/http/headers.rb +4 -4
  59. data/lib/action_dispatch/http/mime_negotiation.rb +26 -13
  60. data/lib/action_dispatch/http/mime_type.rb +43 -24
  61. data/lib/action_dispatch/http/parameters.rb +14 -23
  62. data/lib/action_dispatch/http/permissions_policy.rb +173 -0
  63. data/lib/action_dispatch/http/request.rb +45 -22
  64. data/lib/action_dispatch/http/response.rb +45 -25
  65. data/lib/action_dispatch/http/upload.rb +9 -1
  66. data/lib/action_dispatch/http/url.rb +82 -82
  67. data/lib/action_dispatch/journey/formatter.rb +55 -31
  68. data/lib/action_dispatch/journey/gtg/builder.rb +22 -37
  69. data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
  70. data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -5
  71. data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
  72. data/lib/action_dispatch/journey/nodes/node.rb +13 -11
  73. data/lib/action_dispatch/journey/parser.rb +13 -13
  74. data/lib/action_dispatch/journey/parser.y +1 -1
  75. data/lib/action_dispatch/journey/path/pattern.rb +19 -21
  76. data/lib/action_dispatch/journey/route.rb +10 -20
  77. data/lib/action_dispatch/journey/router/utils.rb +14 -12
  78. data/lib/action_dispatch/journey/router.rb +26 -34
  79. data/lib/action_dispatch/journey/routes.rb +0 -2
  80. data/lib/action_dispatch/journey/scanner.rb +10 -4
  81. data/lib/action_dispatch/journey/visitors.rb +1 -4
  82. data/lib/action_dispatch/journey.rb +0 -2
  83. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  84. data/lib/action_dispatch/middleware/callbacks.rb +2 -4
  85. data/lib/action_dispatch/middleware/cookies.rb +128 -109
  86. data/lib/action_dispatch/middleware/debug_exceptions.rb +43 -66
  87. data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
  88. data/lib/action_dispatch/middleware/debug_view.rb +66 -0
  89. data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -30
  90. data/lib/action_dispatch/middleware/flash.rb +1 -1
  91. data/lib/action_dispatch/middleware/host_authorization.rb +141 -0
  92. data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
  93. data/lib/action_dispatch/middleware/remote_ip.rb +14 -16
  94. data/lib/action_dispatch/middleware/request_id.rb +5 -6
  95. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -3
  96. data/lib/action_dispatch/middleware/session/cookie_store.rb +3 -9
  97. data/lib/action_dispatch/middleware/show_exceptions.rb +3 -2
  98. data/lib/action_dispatch/middleware/ssl.rb +20 -15
  99. data/lib/action_dispatch/middleware/stack.rb +56 -2
  100. data/lib/action_dispatch/middleware/static.rb +153 -93
  101. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  102. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  103. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  104. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
  105. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  106. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
  107. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
  108. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
  109. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
  111. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  112. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +6 -3
  113. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -1
  114. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +104 -8
  115. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
  118. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
  119. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
  120. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  121. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +24 -1
  122. data/lib/action_dispatch/railtie.rb +8 -2
  123. data/lib/action_dispatch/request/session.rb +11 -10
  124. data/lib/action_dispatch/request/utils.rb +26 -2
  125. data/lib/action_dispatch/routing/inspector.rb +100 -52
  126. data/lib/action_dispatch/routing/mapper.rb +155 -103
  127. data/lib/action_dispatch/routing/polymorphic_routes.rb +13 -15
  128. data/lib/action_dispatch/routing/redirection.rb +4 -4
  129. data/lib/action_dispatch/routing/route_set.rb +71 -69
  130. data/lib/action_dispatch/routing/url_for.rb +2 -2
  131. data/lib/action_dispatch/routing.rb +21 -20
  132. data/lib/action_dispatch/system_test_case.rb +54 -11
  133. data/lib/action_dispatch/system_testing/browser.rb +53 -16
  134. data/lib/action_dispatch/system_testing/driver.rb +11 -3
  135. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +49 -7
  136. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +8 -10
  137. data/lib/action_dispatch/testing/assertion_response.rb +0 -1
  138. data/lib/action_dispatch/testing/assertions/response.rb +4 -7
  139. data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
  140. data/lib/action_dispatch/testing/assertions.rb +1 -1
  141. data/lib/action_dispatch/testing/integration.rb +60 -28
  142. data/lib/action_dispatch/testing/request_encoder.rb +2 -2
  143. data/lib/action_dispatch/testing/test_process.rb +29 -4
  144. data/lib/action_dispatch/testing/test_request.rb +3 -3
  145. data/lib/action_dispatch/testing/test_response.rb +4 -32
  146. data/lib/action_dispatch.rb +9 -3
  147. data/lib/action_pack/gem_version.rb +4 -4
  148. data/lib/action_pack.rb +1 -1
  149. metadata +35 -23
  150. data/lib/action_controller/metal/force_ssl.rb +0 -99
  151. data/lib/action_dispatch/http/parameter_filter.rb +0 -86
  152. data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
  153. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
  154. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
  155. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -3,7 +3,6 @@
3
3
  require "rack/session/abstract/id"
4
4
  require "action_controller/metal/exceptions"
5
5
  require "active_support/security_utils"
6
- require "active_support/core_ext/string/strip"
7
6
 
8
7
  module ActionController #:nodoc:
9
8
  class InvalidAuthenticityToken < ActionControllerError #:nodoc:
@@ -18,7 +17,7 @@ module ActionController #:nodoc:
18
17
  # access. When a request reaches your application, \Rails verifies the received
19
18
  # token with the token in the session. All requests are checked except GET requests
20
19
  # as these should be idempotent. Keep in mind that all session-oriented requests
21
- # should be CSRF protected, including JavaScript and HTML requests.
20
+ # are CSRF protected by default, including JavaScript and HTML requests.
22
21
  #
23
22
  # Since HTML and JavaScript requests are typically made from the browser, we
24
23
  # need to ensure to verify request authenticity for the web browser. We can
@@ -31,31 +30,30 @@ module ActionController #:nodoc:
31
30
  # URL on your site. When your JavaScript response loads on their site, it executes.
32
31
  # With carefully crafted JavaScript on their end, sensitive data in your JavaScript
33
32
  # response may be extracted. To prevent this, only XmlHttpRequest (known as XHR or
34
- # Ajax) requests are allowed to make GET requests for JavaScript responses.
33
+ # Ajax) requests are allowed to make requests for JavaScript responses.
35
34
  #
36
- # It's important to remember that XML or JSON requests are also affected and if
37
- # you're building an API you should change forgery protection method in
38
- # <tt>ApplicationController</tt> (by default: <tt>:exception</tt>):
35
+ # Subclasses of <tt>ActionController::Base</tt> are protected by default with the
36
+ # <tt>:exception</tt> strategy, which raises an
37
+ # <tt>ActionController::InvalidAuthenticityToken</tt> error on unverified requests.
38
+ #
39
+ # APIs may want to disable this behavior since they are typically designed to be
40
+ # state-less: that is, the request API client handles the session instead of Rails.
41
+ # One way to achieve this is to use the <tt>:null_session</tt> strategy instead,
42
+ # which allows unverified requests to be handled, but with an empty session:
39
43
  #
40
44
  # class ApplicationController < ActionController::Base
41
- # protect_from_forgery unless: -> { request.format.json? }
45
+ # protect_from_forgery with: :null_session
42
46
  # end
43
47
  #
44
- # CSRF protection is turned on with the <tt>protect_from_forgery</tt> method.
45
- # By default <tt>protect_from_forgery</tt> protects your session with
46
- # <tt>:null_session</tt> method, which provides an empty session
47
- # during request.
48
- #
49
- # We may want to disable CSRF protection for APIs since they are typically
50
- # designed to be state-less. That is, the request API client will handle
51
- # the session for you instead of Rails.
48
+ # Note that API only applications don't include this module or a session middleware
49
+ # by default, and so don't require CSRF protection to be configured.
52
50
  #
53
51
  # The token parameter is named <tt>authenticity_token</tt> by default. The name and
54
52
  # value of this token must be added to every layout that renders forms by including
55
53
  # <tt>csrf_meta_tags</tt> in the HTML +head+.
56
54
  #
57
55
  # Learn more about CSRF attacks and securing your application in the
58
- # {Ruby on Rails Security Guide}[http://guides.rubyonrails.org/security.html].
56
+ # {Ruby on Rails Security Guide}[https://guides.rubyonrails.org/security.html].
59
57
  module RequestForgeryProtection
60
58
  extend ActiveSupport::Concern
61
59
 
@@ -149,7 +147,6 @@ module ActionController #:nodoc:
149
147
  end
150
148
 
151
149
  private
152
-
153
150
  def protection_method_class(name)
154
151
  ActionController::RequestForgeryProtection::ProtectionMethods.const_get(name.to_s.classify)
155
152
  rescue NameError
@@ -173,7 +170,6 @@ module ActionController #:nodoc:
173
170
  end
174
171
 
175
172
  private
176
-
177
173
  class NullSessionHash < Rack::Session::Abstract::SessionHash #:nodoc:
178
174
  def initialize(req)
179
175
  super(nil, req)
@@ -280,7 +276,7 @@ module ActionController #:nodoc:
280
276
 
281
277
  # Check for cross-origin JavaScript responses.
282
278
  def non_xhr_javascript_response? # :doc:
283
- content_type =~ %r(\Atext/javascript) && !request.xhr?
279
+ %r(\A(?:text|application)/javascript).match?(media_type) && !request.xhr?
284
280
  end
285
281
 
286
282
  AUTHENTICITY_TOKEN_LENGTH = 32
@@ -390,7 +386,7 @@ module ActionController #:nodoc:
390
386
  if per_form_csrf_tokens
391
387
  correct_token = per_form_csrf_token(
392
388
  session,
393
- normalize_action_path(request.fullpath),
389
+ request.path.chomp("/"),
394
390
  request.request_method
395
391
  )
396
392
 
@@ -425,9 +421,14 @@ module ActionController #:nodoc:
425
421
  end
426
422
 
427
423
  def xor_byte_strings(s1, s2) # :doc:
428
- s2_bytes = s2.bytes
429
- s1.each_byte.with_index { |c1, i| s2_bytes[i] ^= c1 }
430
- s2_bytes.pack("C*")
424
+ s2 = s2.dup
425
+ size = s1.bytesize
426
+ i = 0
427
+ while i < size
428
+ s2.setbyte(i, s1.getbyte(i) ^ s2.getbyte(i))
429
+ i += 1
430
+ end
431
+ s2
431
432
  end
432
433
 
433
434
  # The form's authenticity parameter. Override to provide your own.
@@ -440,11 +441,11 @@ module ActionController #:nodoc:
440
441
  allow_forgery_protection
441
442
  end
442
443
 
443
- NULL_ORIGIN_MESSAGE = <<-MSG.strip_heredoc
444
+ NULL_ORIGIN_MESSAGE = <<~MSG
444
445
  The browser returned a 'null' origin for a request with origin-based forgery protection turned on. This usually
445
446
  means you have the 'no-referrer' Referrer-Policy header enabled, or that the request came from a site that
446
447
  refused to give its origin. This makes it impossible for Rails to verify the source of the requests. Likely the
447
- best solution is to change your referrer policy to something less strict like same-origin or strict-same-origin.
448
+ best solution is to change your referrer policy to something less strict like same-origin or strict-origin.
448
449
  If you cannot change the referrer policy, you can disable origin checking with the
449
450
  Rails.application.config.action_controller.forgery_protection_origin_check setting.
450
451
  MSG
@@ -474,30 +475,6 @@ module ActionController #:nodoc:
474
475
  end
475
476
  end
476
477
 
477
- if RUBY_VERSION.start_with?("2.2")
478
- # Backported https://github.com/ruby/ruby/commit/6b6680945ed3274cddbc34fdfd410d74081a3e94
479
- using Module.new {
480
- refine Base64.singleton_class do
481
- def urlsafe_encode64(bin, padding: true)
482
- str = strict_encode64(bin).tr("+/", "-_")
483
- str = str.delete("=") unless padding
484
- str
485
- end
486
-
487
- def urlsafe_decode64(str)
488
- # NOTE: RFC 4648 does say nothing about unpadded input, but says that
489
- # "the excess pad characters MAY also be ignored", so it is inferred that
490
- # unpadded input is also acceptable.
491
- str = str.tr("-_", "+/")
492
- if !str.end_with?("=") && str.length % 4 != 0
493
- str = str.ljust((str.length + 3) & ~3, "=")
494
- end
495
- strict_decode64(str)
496
- end
497
- end
498
- }
499
- end
500
-
501
478
  def encode_csrf_token(csrf_token) # :nodoc:
502
479
  if urlsafe_csrf_tokens
503
480
  Base64.urlsafe_encode64(csrf_token, padding: false)
@@ -18,7 +18,7 @@ module ActionController #:nodoc:
18
18
  end
19
19
 
20
20
  private
21
- def process_action(*args)
21
+ def process_action(*)
22
22
  super
23
23
  rescue Exception => exception
24
24
  request.env["action_dispatch.show_detailed_exceptions"] ||= show_detailed_exceptions?
@@ -196,7 +196,6 @@ module ActionController #:nodoc:
196
196
  extend ActiveSupport::Concern
197
197
 
198
198
  private
199
-
200
199
  # Set proper cache control and transfer encoding when streaming
201
200
  def _process_options(options)
202
201
  super
@@ -1,11 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/hash/indifferent_access"
4
- require "active_support/core_ext/hash/transform_values"
5
4
  require "active_support/core_ext/array/wrap"
6
5
  require "active_support/core_ext/string/filters"
7
6
  require "active_support/core_ext/object/to_query"
8
- require "active_support/rescuable"
9
7
  require "action_dispatch/http/upload"
10
8
  require "rack/test"
11
9
  require "stringio"
@@ -21,12 +19,36 @@ module ActionController
21
19
  # params.require(:a)
22
20
  # # => ActionController::ParameterMissing: param is missing or the value is empty: a
23
21
  class ParameterMissing < KeyError
24
- attr_reader :param # :nodoc:
22
+ attr_reader :param, :keys # :nodoc:
25
23
 
26
- def initialize(param) # :nodoc:
24
+ def initialize(param, keys = nil) # :nodoc:
27
25
  @param = param
26
+ @keys = keys
28
27
  super("param is missing or the value is empty: #{param}")
29
28
  end
29
+
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
38
+
39
+ maybe_these.sort_by { |n|
40
+ DidYouMean::Jaro.distance(@error.param.to_s, n)
41
+ }.reverse.first(4)
42
+ else
43
+ []
44
+ end
45
+ end
46
+ 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
30
52
  end
31
53
 
32
54
  # Raised when a supplied parameter is not expected and
@@ -59,7 +81,7 @@ module ActionController
59
81
 
60
82
  # == Action Controller \Parameters
61
83
  #
62
- # Allows you to choose which attributes should be whitelisted for mass updating
84
+ # Allows you to choose which attributes should be permitted for mass updating
63
85
  # and thus prevent accidentally exposing that which shouldn't be exposed.
64
86
  # Provides two methods for this purpose: #require and #permit. The former is
65
87
  # used to mark parameters as required. The latter is used to set the parameter
@@ -133,6 +155,15 @@ module ActionController
133
155
  #
134
156
  # Returns a hash that can be used as the JSON representation for the parameters.
135
157
 
158
+ ##
159
+ # :method: each_key
160
+ #
161
+ # :call-seq:
162
+ # each_key()
163
+ #
164
+ # Calls block once for each key in the parameters, passing the key.
165
+ # If no block is given, an enumerator is returned instead.
166
+
136
167
  ##
137
168
  # :method: empty?
138
169
  #
@@ -173,6 +204,14 @@ module ActionController
173
204
  #
174
205
  # Returns true if the given key is present in the parameters.
175
206
 
207
+ ##
208
+ # :method: member?
209
+ #
210
+ # :call-seq:
211
+ # member?(key)
212
+ #
213
+ # Returns true if the given key is present in the parameters.
214
+
176
215
  ##
177
216
  # :method: keys
178
217
  #
@@ -204,8 +243,8 @@ module ActionController
204
243
  # values()
205
244
  #
206
245
  # Returns a new array of the values of the parameters.
207
- delegate :keys, :key?, :has_key?, :values, :has_value?, :value?, :empty?, :include?,
208
- :as_json, :to_s, to: :@parameters
246
+ delegate :keys, :key?, :has_key?, :member?, :values, :has_value?, :value?, :empty?, :include?,
247
+ :as_json, :to_s, :each_key, to: :@parameters
209
248
 
210
249
  # By default, never raise an UnpermittedParameters exception if these
211
250
  # params are present. The default includes both 'controller' and 'action'
@@ -213,9 +252,15 @@ module ActionController
213
252
  # to change these is to specify `always_permitted_parameters` in your
214
253
  # config. For instance:
215
254
  #
216
- # config.always_permitted_parameters = %w( controller action format )
255
+ # config.action_controller.always_permitted_parameters = %w( controller action format )
217
256
  cattr_accessor :always_permitted_parameters, default: %w( controller action )
218
257
 
258
+ class << self
259
+ def nested_attribute?(key, value) # :nodoc:
260
+ /\A-?\d+\z/.match?(key) && (value.is_a?(Hash) || value.is_a?(Parameters))
261
+ end
262
+ end
263
+
219
264
  # Returns a new instance of <tt>ActionController::Parameters</tt>.
220
265
  # Also, sets the +permitted+ attribute to the default value of
221
266
  # <tt>ActionController::Parameters.permit_all_parameters</tt>.
@@ -246,6 +291,11 @@ module ActionController
246
291
  @parameters == other
247
292
  end
248
293
  end
294
+ alias eql? ==
295
+
296
+ def hash
297
+ [@parameters.hash, @permitted].hash
298
+ end
249
299
 
250
300
  # Returns a safe <tt>ActiveSupport::HashWithIndifferentAccess</tt>
251
301
  # representation of the parameters with all unpermitted keys removed.
@@ -334,6 +384,7 @@ module ActionController
334
384
  # Convert all hashes in values into parameters, then yield each pair in
335
385
  # the same way as <tt>Hash#each_pair</tt>.
336
386
  def each_pair(&block)
387
+ return to_enum(__callee__) unless block_given?
337
388
  @parameters.each_pair do |key, value|
338
389
  yield [key, convert_hashes_to_parameters(key, value)]
339
390
  end
@@ -342,6 +393,17 @@ module ActionController
342
393
  end
343
394
  alias_method :each, :each_pair
344
395
 
396
+ # Convert all hashes in values into parameters, then yield each value in
397
+ # the same way as <tt>Hash#each_value</tt>.
398
+ def each_value(&block)
399
+ return to_enum(:each_value) unless block_given?
400
+ @parameters.each_pair do |key, value|
401
+ yield convert_hashes_to_parameters(key, value)
402
+ end
403
+
404
+ self
405
+ end
406
+
345
407
  # Attribute that keeps track of converted arrays, if any, to avoid double
346
408
  # looping in the common use case permit + mass-assignment. Defined in a
347
409
  # method to instantiate it only if needed.
@@ -442,7 +504,7 @@ module ActionController
442
504
  if value.present? || value == false
443
505
  value
444
506
  else
445
- raise ParameterMissing.new(key)
507
+ raise ParameterMissing.new(key, @parameters.keys)
446
508
  end
447
509
  end
448
510
 
@@ -508,7 +570,7 @@ module ActionController
508
570
  #
509
571
  # Note that if you use +permit+ in a key that points to a hash,
510
572
  # it won't allow all the hash. You also need to specify which
511
- # attributes inside the hash should be whitelisted.
573
+ # attributes inside the hash should be permitted.
512
574
  #
513
575
  # params = ActionController::Parameters.new({
514
576
  # person: {
@@ -579,26 +641,24 @@ module ActionController
579
641
  if block_given?
580
642
  yield
581
643
  else
582
- args.fetch(0) { raise ActionController::ParameterMissing.new(key) }
644
+ args.fetch(0) { raise ActionController::ParameterMissing.new(key, @parameters.keys) }
583
645
  end
584
646
  }
585
647
  )
586
648
  end
587
649
 
588
- if Hash.method_defined?(:dig)
589
- # Extracts the nested parameter from the given +keys+ by calling +dig+
590
- # at each step. Returns +nil+ if any intermediate step is +nil+.
591
- #
592
- # params = ActionController::Parameters.new(foo: { bar: { baz: 1 } })
593
- # params.dig(:foo, :bar, :baz) # => 1
594
- # params.dig(:foo, :zot, :xyz) # => nil
595
- #
596
- # params2 = ActionController::Parameters.new(foo: [10, 11, 12])
597
- # params2.dig(:foo, 1) # => 11
598
- def dig(*keys)
599
- convert_hashes_to_parameters(keys.first, @parameters[keys.first])
600
- @parameters.dig(*keys)
601
- end
650
+ # Extracts the nested parameter from the given +keys+ by calling +dig+
651
+ # at each step. Returns +nil+ if any intermediate step is +nil+.
652
+ #
653
+ # params = ActionController::Parameters.new(foo: { bar: { baz: 1 } })
654
+ # params.dig(:foo, :bar, :baz) # => 1
655
+ # params.dig(:foo, :zot, :xyz) # => nil
656
+ #
657
+ # params2 = ActionController::Parameters.new(foo: [10, 11, 12])
658
+ # params2.dig(:foo, 1) # => 11
659
+ def dig(*keys)
660
+ convert_hashes_to_parameters(keys.first, @parameters[keys.first])
661
+ @parameters.dig(*keys)
602
662
  end
603
663
 
604
664
  # Returns a new <tt>ActionController::Parameters</tt> instance that
@@ -662,22 +722,37 @@ module ActionController
662
722
  # Returns a new <tt>ActionController::Parameters</tt> instance with the
663
723
  # results of running +block+ once for every key. The values are unchanged.
664
724
  def transform_keys(&block)
665
- if block
666
- new_instance_with_inherited_permitted_status(
667
- @parameters.transform_keys(&block)
668
- )
669
- else
670
- @parameters.transform_keys
671
- end
725
+ return to_enum(:transform_keys) unless block_given?
726
+ new_instance_with_inherited_permitted_status(
727
+ @parameters.transform_keys(&block)
728
+ )
672
729
  end
673
730
 
674
731
  # Performs keys transformation and returns the altered
675
732
  # <tt>ActionController::Parameters</tt> instance.
676
733
  def transform_keys!(&block)
734
+ return to_enum(:transform_keys!) unless block_given?
677
735
  @parameters.transform_keys!(&block)
678
736
  self
679
737
  end
680
738
 
739
+ # Returns a new <tt>ActionController::Parameters</tt> instance with the
740
+ # results of running +block+ once for every key. This includes the keys
741
+ # from the root hash and from all nested hashes and arrays. The values are unchanged.
742
+ def deep_transform_keys(&block)
743
+ new_instance_with_inherited_permitted_status(
744
+ @parameters.deep_transform_keys(&block)
745
+ )
746
+ end
747
+
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.
751
+ def deep_transform_keys!(&block)
752
+ @parameters.deep_transform_keys!(&block)
753
+ self
754
+ end
755
+
681
756
  # Deletes a key-value pair from +Parameters+ and returns the value. If
682
757
  # +key+ is not found, returns +nil+ (or, with optional code block, yields
683
758
  # +key+ and returns the result). Cf. +#extract!+, which returns the
@@ -712,6 +787,28 @@ module ActionController
712
787
  end
713
788
  alias_method :delete_if, :reject!
714
789
 
790
+ # Returns a new instance of <tt>ActionController::Parameters</tt> with +nil+ values removed.
791
+ def compact
792
+ new_instance_with_inherited_permitted_status(@parameters.compact)
793
+ end
794
+
795
+ # Removes all +nil+ values in place and returns +self+, or +nil+ if no changes were made.
796
+ def compact!
797
+ self if @parameters.compact!
798
+ end
799
+
800
+ # Returns a new instance of <tt>ActionController::Parameters</tt> without the blank values.
801
+ # Uses Object#blank? for determining if a value is blank.
802
+ def compact_blank
803
+ reject { |_k, v| v.blank? }
804
+ end
805
+
806
+ # Removes all blank values in place and returns self.
807
+ # Uses Object#blank? for determining if a value is blank.
808
+ def compact_blank!
809
+ reject! { |_k, v| v.blank? }
810
+ end
811
+
715
812
  # Returns values that were assigned to the given +keys+. Note that all the
716
813
  # +Hash+ objects will be converted to <tt>ActionController::Parameters</tt>.
717
814
  def values_at(*keys)
@@ -758,7 +855,7 @@ module ActionController
758
855
  end
759
856
 
760
857
  def inspect
761
- "<#{self.class} #{@parameters} permitted: #{@permitted}>"
858
+ "#<#{self.class} #{@parameters} permitted: #{@permitted}>"
762
859
  end
763
860
 
764
861
  def self.hook_into_yaml_loading # :nodoc:
@@ -783,7 +880,7 @@ module ActionController
783
880
  @permitted = coder.map["ivars"][:@permitted]
784
881
  when "!ruby/object:ActionController::Parameters"
785
882
  # YAML's Object format. Only needed because of the format
786
- # backwardscompability above, otherwise equivalent to YAML's initialization.
883
+ # backwards compatibility above, otherwise equivalent to YAML's initialization.
787
884
  @parameters, @permitted = coder.map["parameters"], coder.map["permitted"]
788
885
  end
789
886
  end
@@ -798,12 +895,16 @@ module ActionController
798
895
  protected
799
896
  attr_reader :parameters
800
897
 
801
- def permitted=(new_permitted)
802
- @permitted = new_permitted
898
+ attr_writer :permitted
899
+
900
+ def nested_attributes?
901
+ @parameters.any? { |k, v| Parameters.nested_attribute?(k, v) }
803
902
  end
804
903
 
805
- def fields_for_style?
806
- @parameters.all? { |k, v| k =~ /\A-?\d+\z/ && (v.is_a?(Hash) || v.is_a?(Parameters)) }
904
+ def each_nested_attribute
905
+ hash = self.class.new
906
+ self.each { |k, v| hash[k] = yield v if Parameters.nested_attribute?(k, v) }
907
+ hash
807
908
  end
808
909
 
809
910
  private
@@ -848,15 +949,13 @@ module ActionController
848
949
  end
849
950
  end
850
951
 
851
- def each_element(object)
952
+ def each_element(object, &block)
852
953
  case object
853
954
  when Array
854
955
  object.grep(Parameters).map { |el| yield el }.compact
855
956
  when Parameters
856
- if object.fields_for_style?
857
- hash = object.class.new
858
- object.each { |k, v| hash[k] = yield v }
859
- hash
957
+ if object.nested_attributes?
958
+ object.each_nested_attribute(&block)
860
959
  else
861
960
  yield object
862
961
  end
@@ -884,7 +983,7 @@ module ActionController
884
983
  # --- Filtering ----------------------------------------------------------
885
984
  #
886
985
 
887
- # This is a white list of permitted scalar types that includes the ones
986
+ # This is a list of permitted scalar types that includes the ones
888
987
  # supported in XML and JSON requests.
889
988
  #
890
989
  # This list is in particular used to filter ordinary requests, String goes
@@ -911,15 +1010,28 @@ module ActionController
911
1010
  PERMITTED_SCALAR_TYPES.any? { |type| value.is_a?(type) }
912
1011
  end
913
1012
 
914
- def permitted_scalar_filter(params, key)
915
- if has_key?(key) && permitted_scalar?(self[key])
916
- params[key] = self[key]
1013
+ # Adds existing keys to the params if their values are scalar.
1014
+ #
1015
+ # For example:
1016
+ #
1017
+ # puts self.keys #=> ["zipcode(90210i)"]
1018
+ # params = {}
1019
+ #
1020
+ # permitted_scalar_filter(params, "zipcode")
1021
+ #
1022
+ # puts params.keys # => ["zipcode"]
1023
+ def permitted_scalar_filter(params, permitted_key)
1024
+ permitted_key = permitted_key.to_s
1025
+
1026
+ if has_key?(permitted_key) && permitted_scalar?(self[permitted_key])
1027
+ params[permitted_key] = self[permitted_key]
917
1028
  end
918
1029
 
919
- keys.grep(/\A#{Regexp.escape(key)}\(\d+[if]?\)\z/) do |k|
920
- if permitted_scalar?(self[k])
921
- params[k] = self[k]
922
- end
1030
+ each_key do |key|
1031
+ next unless key =~ /\(\d+[if]?\)\z/
1032
+ next unless $~.pre_match == permitted_key
1033
+
1034
+ params[key] = self[key] if permitted_scalar?(self[key])
923
1035
  end
924
1036
  end
925
1037
 
@@ -1004,8 +1116,8 @@ module ActionController
1004
1116
  #
1005
1117
  # It provides an interface for protecting attributes from end-user
1006
1118
  # assignment. This makes Action Controller parameters forbidden
1007
- # to be used in Active Model mass assignment until they have been
1008
- # whitelisted.
1119
+ # to be used in Active Model mass assignment until they have been explicitly
1120
+ # enumerated.
1009
1121
  #
1010
1122
  # In addition, parameters can be marked as required and flow through a
1011
1123
  # predefined raise/rescue flow to end up as a <tt>400 Bad Request</tt> with no
@@ -1041,7 +1153,7 @@ module ActionController
1041
1153
  # end
1042
1154
  #
1043
1155
  # In order to use <tt>accepts_nested_attributes_for</tt> with Strong \Parameters, you
1044
- # will need to specify which nested attributes should be whitelisted. You might want
1156
+ # will need to specify which nested attributes should be permitted. You might want
1045
1157
  # to allow +:id+ and +:_destroy+, see ActiveRecord::NestedAttributes for more information.
1046
1158
  #
1047
1159
  # class Person
@@ -1059,7 +1171,7 @@ module ActionController
1059
1171
  # private
1060
1172
  #
1061
1173
  # def person_params
1062
- # # It's mandatory to specify the nested attributes that should be whitelisted.
1174
+ # # It's mandatory to specify the nested attributes that should be permitted.
1063
1175
  # # If you use `permit` with just the key that points to the nested attributes hash,
1064
1176
  # # it will return an empty hash.
1065
1177
  # params.require(:person).permit(:name, :age, pets_attributes: [ :id, :name, :category ])
@@ -1069,9 +1181,6 @@ module ActionController
1069
1181
  # See ActionController::Parameters.require and ActionController::Parameters.permit
1070
1182
  # for more information.
1071
1183
  module StrongParameters
1072
- extend ActiveSupport::Concern
1073
- include ActiveSupport::Rescuable
1074
-
1075
1184
  # Returns a new ActionController::Parameters object that
1076
1185
  # has been instantiated with the <tt>request.parameters</tt>.
1077
1186
  def params
@@ -44,7 +44,7 @@ module ActionController
44
44
  options[:original_script_name] = original_script_name
45
45
  else
46
46
  if same_origin
47
- options[:script_name] = request.script_name.empty? ? "".freeze : request.script_name.dup
47
+ options[:script_name] = request.script_name.empty? ? "" : request.script_name.dup
48
48
  else
49
49
  options[:script_name] = script_name
50
50
  end
@@ -35,7 +35,6 @@ module ActionController
35
35
  end
36
36
 
37
37
  private
38
-
39
38
  INCLUDE = ->(list, action) { list.include? action }
40
39
  EXCLUDE = ->(list, action) { !list.include? action }
41
40
  NULL = ->(list, action) { true }
@@ -127,7 +126,7 @@ module ActionController
127
126
  # ==== Returns
128
127
  # * <tt>string</tt>
129
128
  def self.controller_name
130
- @controller_name ||= name.demodulize.sub(/Controller$/, "").underscore
129
+ @controller_name ||= (name.demodulize.delete_suffix("Controller").underscore unless anonymous?)
131
130
  end
132
131
 
133
132
  def self.make_response!(request)
@@ -136,7 +135,7 @@ module ActionController
136
135
  end
137
136
  end
138
137
 
139
- def self.binary_params_for?(action) # :nodoc:
138
+ def self.action_encoding_template(action) # :nodoc:
140
139
  false
141
140
  end
142
141
 
@@ -148,7 +147,7 @@ module ActionController
148
147
  attr_internal :response, :request
149
148
  delegate :session, to: "@_request"
150
149
  delegate :headers, :status=, :location=, :content_type=,
151
- :status, :location, :content_type, to: "@_response"
150
+ :status, :location, :content_type, :media_type, to: "@_response"
152
151
 
153
152
  def initialize
154
153
  @_request = nil
@@ -217,10 +216,13 @@ module ActionController
217
216
  super
218
217
  end
219
218
 
220
- # Pushes the given Rack middleware and its arguments to the bottom of the
221
- # middleware stack.
222
- def self.use(*args, &block)
223
- middleware_stack.use(*args, &block)
219
+ class << self
220
+ # Pushes the given Rack middleware and its arguments to the bottom of the
221
+ # middleware stack.
222
+ def use(*args, &block)
223
+ middleware_stack.use(*args, &block)
224
+ end
225
+ ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
224
226
  end
225
227
 
226
228
  # Alias for +middleware_stack+.
@@ -7,7 +7,7 @@ module ActionController
7
7
  super
8
8
  return unless klass.respond_to?(:helpers_path=)
9
9
 
10
- if namespace = klass.parents.detect { |m| m.respond_to?(:railtie_helpers_paths) }
10
+ if namespace = klass.module_parents.detect { |m| m.respond_to?(:railtie_helpers_paths) }
11
11
  paths = namespace.railtie_helpers_paths
12
12
  else
13
13
  paths = ActionController::Helpers.helpers_path