actionpack 5.2.0 → 6.1.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 (156) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +408 -190
  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 +2 -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 +25 -24
  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 +33 -23
  38. data/lib/action_controller/metal/permissions_policy.rb +46 -0
  39. data/lib/action_controller/metal/redirecting.rb +7 -7
  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 +89 -36
  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 +181 -69
  46. data/lib/action_controller/metal/url_for.rb +1 -1
  47. data/lib/action_controller/metal.rb +12 -10
  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 +81 -70
  52. data/lib/action_controller.rb +7 -4
  53. data/lib/action_dispatch/http/cache.rb +34 -28
  54. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  55. data/lib/action_dispatch/http/content_security_policy.rb +47 -24
  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 +31 -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 +21 -22
  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 +1 -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 +2 -2
  91. data/lib/action_dispatch/middleware/host_authorization.rb +130 -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 +15 -2
  96. data/lib/action_dispatch/middleware/session/cache_store.rb +11 -6
  97. data/lib/action_dispatch/middleware/session/cookie_store.rb +24 -19
  98. data/lib/action_dispatch/middleware/show_exceptions.rb +3 -2
  99. data/lib/action_dispatch/middleware/ssl.rb +20 -15
  100. data/lib/action_dispatch/middleware/stack.rb +57 -3
  101. data/lib/action_dispatch/middleware/static.rb +153 -93
  102. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  103. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  104. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  105. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
  106. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  107. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
  108. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
  109. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
  111. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
  112. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  113. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +6 -3
  114. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -1
  115. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +104 -8
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
  119. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  122. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +24 -1
  123. data/lib/action_dispatch/railtie.rb +8 -2
  124. data/lib/action_dispatch/request/session.rb +17 -10
  125. data/lib/action_dispatch/request/utils.rb +28 -2
  126. data/lib/action_dispatch/routing/inspector.rb +101 -53
  127. data/lib/action_dispatch/routing/mapper.rb +156 -103
  128. data/lib/action_dispatch/routing/polymorphic_routes.rb +21 -19
  129. data/lib/action_dispatch/routing/redirection.rb +4 -4
  130. data/lib/action_dispatch/routing/route_set.rb +71 -69
  131. data/lib/action_dispatch/routing/url_for.rb +3 -3
  132. data/lib/action_dispatch/routing.rb +21 -20
  133. data/lib/action_dispatch/system_test_case.rb +54 -11
  134. data/lib/action_dispatch/system_testing/browser.rb +53 -16
  135. data/lib/action_dispatch/system_testing/driver.rb +11 -3
  136. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +49 -7
  137. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +8 -6
  138. data/lib/action_dispatch/testing/assertion_response.rb +0 -1
  139. data/lib/action_dispatch/testing/assertions/response.rb +4 -7
  140. data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
  141. data/lib/action_dispatch/testing/assertions.rb +1 -1
  142. data/lib/action_dispatch/testing/integration.rb +61 -28
  143. data/lib/action_dispatch/testing/request_encoder.rb +3 -3
  144. data/lib/action_dispatch/testing/test_process.rb +29 -4
  145. data/lib/action_dispatch/testing/test_request.rb +3 -3
  146. data/lib/action_dispatch/testing/test_response.rb +4 -32
  147. data/lib/action_dispatch.rb +14 -7
  148. data/lib/action_pack/gem_version.rb +3 -3
  149. data/lib/action_pack.rb +1 -1
  150. metadata +39 -22
  151. data/lib/action_controller/metal/force_ssl.rb +0 -99
  152. data/lib/action_dispatch/http/parameter_filter.rb +0 -86
  153. data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
  154. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
  155. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
  156. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -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,12 +384,26 @@ 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
391
+
392
+ self
340
393
  end
341
394
  alias_method :each, :each_pair
342
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
+
343
407
  # Attribute that keeps track of converted arrays, if any, to avoid double
344
408
  # looping in the common use case permit + mass-assignment. Defined in a
345
409
  # method to instantiate it only if needed.
@@ -375,7 +439,7 @@ module ActionController
375
439
  # Person.new(params) # => #<Person id: nil, name: "Francesco">
376
440
  def permit!
377
441
  each_pair do |key, value|
378
- Array.wrap(value).each do |v|
442
+ Array.wrap(value).flatten.each do |v|
379
443
  v.permit! if v.respond_to? :permit!
380
444
  end
381
445
  end
@@ -440,7 +504,7 @@ module ActionController
440
504
  if value.present? || value == false
441
505
  value
442
506
  else
443
- raise ParameterMissing.new(key)
507
+ raise ParameterMissing.new(key, @parameters.keys)
444
508
  end
445
509
  end
446
510
 
@@ -506,7 +570,7 @@ module ActionController
506
570
  #
507
571
  # Note that if you use +permit+ in a key that points to a hash,
508
572
  # it won't allow all the hash. You also need to specify which
509
- # attributes inside the hash should be whitelisted.
573
+ # attributes inside the hash should be permitted.
510
574
  #
511
575
  # params = ActionController::Parameters.new({
512
576
  # person: {
@@ -561,12 +625,14 @@ module ActionController
561
625
  # Returns a parameter for the given +key+. If the +key+
562
626
  # can't be found, there are several options: With no other arguments,
563
627
  # it will raise an <tt>ActionController::ParameterMissing</tt> error;
564
- # if more arguments are given, then that will be returned; if a block
628
+ # if a second argument is given, then that is returned (converted to an
629
+ # instance of ActionController::Parameters if possible); if a block
565
630
  # is given, then that will be run and its result returned.
566
631
  #
567
632
  # params = ActionController::Parameters.new(person: { name: "Francesco" })
568
633
  # params.fetch(:person) # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
569
634
  # params.fetch(:none) # => ActionController::ParameterMissing: param is missing or the value is empty: none
635
+ # params.fetch(:none, {}) # => <ActionController::Parameters {} permitted: false>
570
636
  # params.fetch(:none, "Francesco") # => "Francesco"
571
637
  # params.fetch(:none) { "Francesco" } # => "Francesco"
572
638
  def fetch(key, *args)
@@ -575,25 +641,24 @@ module ActionController
575
641
  if block_given?
576
642
  yield
577
643
  else
578
- args.fetch(0) { raise ActionController::ParameterMissing.new(key) }
644
+ args.fetch(0) { raise ActionController::ParameterMissing.new(key, @parameters.keys) }
579
645
  end
580
646
  }
581
647
  )
582
648
  end
583
649
 
584
- if Hash.method_defined?(:dig)
585
- # Extracts the nested parameter from the given +keys+ by calling +dig+
586
- # at each step. Returns +nil+ if any intermediate step is +nil+.
587
- #
588
- # params = ActionController::Parameters.new(foo: { bar: { baz: 1 } })
589
- # params.dig(:foo, :bar, :baz) # => 1
590
- # params.dig(:foo, :zot, :xyz) # => nil
591
- #
592
- # params2 = ActionController::Parameters.new(foo: [10, 11, 12])
593
- # params2.dig(:foo, 1) # => 11
594
- def dig(*keys)
595
- convert_value_to_parameters(@parameters.dig(*keys))
596
- 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)
597
662
  end
598
663
 
599
664
  # Returns a new <tt>ActionController::Parameters</tt> instance that
@@ -639,42 +704,55 @@ module ActionController
639
704
  # params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
640
705
  # params.transform_values { |x| x * 2 }
641
706
  # # => <ActionController::Parameters {"a"=>2, "b"=>4, "c"=>6} permitted: false>
642
- def transform_values(&block)
643
- if block
644
- new_instance_with_inherited_permitted_status(
645
- @parameters.transform_values(&block)
646
- )
647
- else
648
- @parameters.transform_values
649
- end
707
+ def transform_values
708
+ return to_enum(:transform_values) unless block_given?
709
+ new_instance_with_inherited_permitted_status(
710
+ @parameters.transform_values { |v| yield convert_value_to_parameters(v) }
711
+ )
650
712
  end
651
713
 
652
714
  # Performs values transformation and returns the altered
653
715
  # <tt>ActionController::Parameters</tt> instance.
654
- def transform_values!(&block)
655
- @parameters.transform_values!(&block)
716
+ def transform_values!
717
+ return to_enum(:transform_values!) unless block_given?
718
+ @parameters.transform_values! { |v| yield convert_value_to_parameters(v) }
656
719
  self
657
720
  end
658
721
 
659
722
  # Returns a new <tt>ActionController::Parameters</tt> instance with the
660
723
  # results of running +block+ once for every key. The values are unchanged.
661
724
  def transform_keys(&block)
662
- if block
663
- new_instance_with_inherited_permitted_status(
664
- @parameters.transform_keys(&block)
665
- )
666
- else
667
- @parameters.transform_keys
668
- end
725
+ return to_enum(:transform_keys) unless block_given?
726
+ new_instance_with_inherited_permitted_status(
727
+ @parameters.transform_keys(&block)
728
+ )
669
729
  end
670
730
 
671
731
  # Performs keys transformation and returns the altered
672
732
  # <tt>ActionController::Parameters</tt> instance.
673
733
  def transform_keys!(&block)
734
+ return to_enum(:transform_keys!) unless block_given?
674
735
  @parameters.transform_keys!(&block)
675
736
  self
676
737
  end
677
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
+
678
756
  # Deletes a key-value pair from +Parameters+ and returns the value. If
679
757
  # +key+ is not found, returns +nil+ (or, with optional code block, yields
680
758
  # +key+ and returns the result). Cf. +#extract!+, which returns the
@@ -709,6 +787,28 @@ module ActionController
709
787
  end
710
788
  alias_method :delete_if, :reject!
711
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
+
712
812
  # Returns values that were assigned to the given +keys+. Note that all the
713
813
  # +Hash+ objects will be converted to <tt>ActionController::Parameters</tt>.
714
814
  def values_at(*keys)
@@ -755,7 +855,7 @@ module ActionController
755
855
  end
756
856
 
757
857
  def inspect
758
- "<#{self.class} #{@parameters} permitted: #{@permitted}>"
858
+ "#<#{self.class} #{@parameters} permitted: #{@permitted}>"
759
859
  end
760
860
 
761
861
  def self.hook_into_yaml_loading # :nodoc:
@@ -780,7 +880,7 @@ module ActionController
780
880
  @permitted = coder.map["ivars"][:@permitted]
781
881
  when "!ruby/object:ActionController::Parameters"
782
882
  # YAML's Object format. Only needed because of the format
783
- # backwardscompability above, otherwise equivalent to YAML's initialization.
883
+ # backwards compatibility above, otherwise equivalent to YAML's initialization.
784
884
  @parameters, @permitted = coder.map["parameters"], coder.map["permitted"]
785
885
  end
786
886
  end
@@ -795,12 +895,16 @@ module ActionController
795
895
  protected
796
896
  attr_reader :parameters
797
897
 
798
- def permitted=(new_permitted)
799
- @permitted = new_permitted
898
+ attr_writer :permitted
899
+
900
+ def nested_attributes?
901
+ @parameters.any? { |k, v| Parameters.nested_attribute?(k, v) }
800
902
  end
801
903
 
802
- def fields_for_style?
803
- @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
804
908
  end
805
909
 
806
910
  private
@@ -845,15 +949,13 @@ module ActionController
845
949
  end
846
950
  end
847
951
 
848
- def each_element(object)
952
+ def each_element(object, &block)
849
953
  case object
850
954
  when Array
851
955
  object.grep(Parameters).map { |el| yield el }.compact
852
956
  when Parameters
853
- if object.fields_for_style?
854
- hash = object.class.new
855
- object.each { |k, v| hash[k] = yield v }
856
- hash
957
+ if object.nested_attributes?
958
+ object.each_nested_attribute(&block)
857
959
  else
858
960
  yield object
859
961
  end
@@ -881,7 +983,7 @@ module ActionController
881
983
  # --- Filtering ----------------------------------------------------------
882
984
  #
883
985
 
884
- # 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
885
987
  # supported in XML and JSON requests.
886
988
  #
887
989
  # This list is in particular used to filter ordinary requests, String goes
@@ -908,15 +1010,28 @@ module ActionController
908
1010
  PERMITTED_SCALAR_TYPES.any? { |type| value.is_a?(type) }
909
1011
  end
910
1012
 
911
- def permitted_scalar_filter(params, key)
912
- if has_key?(key) && permitted_scalar?(self[key])
913
- 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]
914
1028
  end
915
1029
 
916
- keys.grep(/\A#{Regexp.escape(key)}\(\d+[if]?\)\z/) do |k|
917
- if permitted_scalar?(self[k])
918
- params[k] = self[k]
919
- 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])
920
1035
  end
921
1036
  end
922
1037
 
@@ -1001,8 +1116,8 @@ module ActionController
1001
1116
  #
1002
1117
  # It provides an interface for protecting attributes from end-user
1003
1118
  # assignment. This makes Action Controller parameters forbidden
1004
- # to be used in Active Model mass assignment until they have been
1005
- # whitelisted.
1119
+ # to be used in Active Model mass assignment until they have been explicitly
1120
+ # enumerated.
1006
1121
  #
1007
1122
  # In addition, parameters can be marked as required and flow through a
1008
1123
  # predefined raise/rescue flow to end up as a <tt>400 Bad Request</tt> with no
@@ -1038,7 +1153,7 @@ module ActionController
1038
1153
  # end
1039
1154
  #
1040
1155
  # In order to use <tt>accepts_nested_attributes_for</tt> with Strong \Parameters, you
1041
- # 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
1042
1157
  # to allow +:id+ and +:_destroy+, see ActiveRecord::NestedAttributes for more information.
1043
1158
  #
1044
1159
  # class Person
@@ -1056,7 +1171,7 @@ module ActionController
1056
1171
  # private
1057
1172
  #
1058
1173
  # def person_params
1059
- # # 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.
1060
1175
  # # If you use `permit` with just the key that points to the nested attributes hash,
1061
1176
  # # it will return an empty hash.
1062
1177
  # params.require(:person).permit(:name, :age, pets_attributes: [ :id, :name, :category ])
@@ -1066,9 +1181,6 @@ module ActionController
1066
1181
  # See ActionController::Parameters.require and ActionController::Parameters.permit
1067
1182
  # for more information.
1068
1183
  module StrongParameters
1069
- extend ActiveSupport::Concern
1070
- include ActiveSupport::Rescuable
1071
-
1072
1184
  # Returns a new ActionController::Parameters object that
1073
1185
  # has been instantiated with the <tt>request.parameters</tt>.
1074
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
@@ -26,16 +26,15 @@ module ActionController
26
26
  end
27
27
  end
28
28
 
29
- def build(action, app = Proc.new)
29
+ def build(action, app = nil, &block)
30
30
  action = action.to_s
31
31
 
32
- middlewares.reverse.inject(app) do |a, middleware|
32
+ middlewares.reverse.inject(app || block) do |a, middleware|
33
33
  middleware.valid?(action) ? middleware.build(a) : a
34
34
  end
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
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/hash/keys"
4
-
5
3
  module ActionController
6
4
  # ActionController::Renderer allows you to render arbitrary templates
7
5
  # without requirement of being in controller actions.
@@ -67,10 +65,29 @@ module ActionController
67
65
  def initialize(controller, env, defaults)
68
66
  @controller = controller
69
67
  @defaults = defaults
70
- @env = normalize_keys defaults.merge(env)
68
+ @env = normalize_keys defaults, env
71
69
  end
72
70
 
73
71
  # Render templates with any options from ActionController::Base#render_to_string.
72
+ #
73
+ # The primary options are:
74
+ # * <tt>:partial</tt> - See <tt>ActionView::PartialRenderer</tt> for details.
75
+ # * <tt>:file</tt> - Renders an explicit template file. Add <tt>:locals</tt> to pass in, if so desired.
76
+ # It shouldn’t be used directly with unsanitized user input due to lack of validation.
77
+ # * <tt>:inline</tt> - Renders an ERB template string.
78
+ # * <tt>:plain</tt> - Renders provided text and sets the content type as <tt>text/plain</tt>.
79
+ # * <tt>:html</tt> - Renders the provided HTML safe string, otherwise
80
+ # performs HTML escape on the string first. Sets the content type as <tt>text/html</tt>.
81
+ # * <tt>:json</tt> - Renders the provided hash or object in JSON. You don't
82
+ # need to call <tt>.to_json</tt> on the object you want to render.
83
+ # * <tt>:body</tt> - Renders provided text and sets content type of <tt>text/plain</tt>.
84
+ #
85
+ # If no <tt>options</tt> hash is passed or if <tt>:update</tt> is specified, then:
86
+ #
87
+ # If an object responding to +render_in+ is passed, +render_in+ is called on the object,
88
+ # passing in the current view context.
89
+ #
90
+ # Otherwise, a partial is rendered using the second parameter as the locals hash.
74
91
  def render(*args)
75
92
  raise "missing controller" unless controller
76
93
 
@@ -82,11 +99,18 @@ module ActionController
82
99
  instance.set_response! controller.make_response!(request)
83
100
  instance.render_to_string(*args)
84
101
  end
102
+ alias_method :render_to_string, :render # :nodoc:
85
103
 
86
104
  private
87
- def normalize_keys(env)
105
+ def normalize_keys(defaults, env)
88
106
  new_env = {}
89
107
  env.each_pair { |k, v| new_env[rack_key_for(k)] = rack_value_for(k, v) }
108
+
109
+ defaults.each_pair do |k, v|
110
+ key = rack_key_for(k)
111
+ new_env[key] = rack_value_for(k, v) unless new_env.key?(key)
112
+ end
113
+
90
114
  new_env["rack.url_scheme"] = new_env["HTTPS"] == "on" ? "https" : "http"
91
115
  new_env
92
116
  end
@@ -99,19 +123,19 @@ module ActionController
99
123
  input: "rack.input"
100
124
  }
101
125
 
102
- IDENTITY = ->(_) { _ }
103
-
104
- RACK_VALUE_TRANSLATION = {
105
- https: ->(v) { v ? "on" : "off" },
106
- method: ->(v) { v.upcase },
107
- }
108
-
109
126
  def rack_key_for(key)
110
- RACK_KEY_TRANSLATION.fetch(key, key.to_s)
127
+ RACK_KEY_TRANSLATION[key] || key.to_s
111
128
  end
112
129
 
113
130
  def rack_value_for(key, value)
114
- RACK_VALUE_TRANSLATION.fetch(key, IDENTITY).call value
131
+ case key
132
+ when :https
133
+ value ? "on" : "off"
134
+ when :method
135
+ -value.upcase
136
+ else
137
+ value
138
+ end
115
139
  end
116
140
  end
117
141
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionController
4
- module TemplateAssertions
4
+ module TemplateAssertions # :nodoc:
5
5
  def assert_template(options = {}, message = nil)
6
6
  raise NoMethodError,
7
7
  "assert_template has been extracted to a gem. To continue using it,