actionpack 7.0.10 → 7.1.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +318 -452
  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 +11 -5
  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 +4 -2
  35. data/lib/action_controller/metal/permissions_policy.rb +1 -1
  36. data/lib/action_controller/metal/redirecting.rb +7 -7
  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 +13 -29
  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 +22 -22
  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 +45 -16
  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 -7
  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 -16
  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 +44 -33
@@ -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,
@@ -4,6 +4,8 @@ require "active_support/core_ext/array/extract_options"
4
4
  require "action_dispatch/middleware/stack"
5
5
 
6
6
  module ActionController
7
+ # = Action Controller \MiddlewareStack
8
+ #
7
9
  # Extend ActionDispatch middleware stack to make it aware of options
8
10
  # allowing the following syntax in controllers:
9
11
  #
@@ -58,7 +60,9 @@ module ActionController
58
60
  end
59
61
  end
60
62
 
61
- # <tt>ActionController::Metal</tt> is the simplest possible controller, providing a
63
+ # = Action Controller \Metal
64
+ #
65
+ # +ActionController::Metal+ is the simplest possible controller, providing a
62
66
  # valid Rack interface without the additional niceties provided by
63
67
  # ActionController::Base.
64
68
  #
@@ -78,9 +82,9 @@ module ActionController
78
82
  # The +action+ method returns a valid Rack application for the \Rails
79
83
  # router to dispatch to.
80
84
  #
81
- # == Rendering Helpers
85
+ # == \Rendering \Helpers
82
86
  #
83
- # <tt>ActionController::Metal</tt> by default provides no utilities for rendering
87
+ # +ActionController::Metal+ by default provides no utilities for rendering
84
88
  # views, partials, or other responses aside from explicitly calling of
85
89
  # <tt>response_body=</tt>, <tt>content_type=</tt>, and <tt>status=</tt>. To
86
90
  # add the render helpers you're used to having in a normal controller, you
@@ -96,7 +100,7 @@ module ActionController
96
100
  # end
97
101
  # end
98
102
  #
99
- # == Redirection Helpers
103
+ # == Redirection \Helpers
100
104
  #
101
105
  # To add redirection helpers to your metal controller, do the following:
102
106
  #
@@ -109,7 +113,7 @@ module ActionController
109
113
  # end
110
114
  # end
111
115
  #
112
- # == Other Helpers
116
+ # == Other \Helpers
113
117
  #
114
118
  # You can refer to the modules included in ActionController::Base to see
115
119
  # other features you can bring into your metal controller.
@@ -118,8 +122,8 @@ module ActionController
118
122
  abstract!
119
123
 
120
124
  # Returns the last part of the controller's name, underscored, without the ending
121
- # <tt>Controller</tt>. For instance, PostsController returns <tt>posts</tt>.
122
- # Namespaces are left out, so Admin::PostsController returns <tt>posts</tt> as well.
125
+ # <tt>Controller</tt>. For instance, +PostsController+ returns <tt>posts</tt>.
126
+ # Namespaces are left out, so +Admin::PostsController+ returns <tt>posts</tt> as well.
123
127
  #
124
128
  # ==== Returns
125
129
  # * <tt>string</tt>
@@ -137,20 +141,53 @@ module ActionController
137
141
  false
138
142
  end
139
143
 
144
+ class << self
145
+ private
146
+ def inherited(subclass)
147
+ super
148
+ subclass.middleware_stack = middleware_stack.dup
149
+ subclass.class_eval do
150
+ @controller_name = nil
151
+ end
152
+ end
153
+ end
154
+
140
155
  # Delegates to the class's ::controller_name.
141
156
  def controller_name
142
157
  self.class.controller_name
143
158
  end
144
159
 
145
- attr_internal :response, :request
160
+ ##
161
+ # :attr_reader: request
162
+ #
163
+ # The ActionDispatch::Request instance for the current request.
164
+ attr_internal :request
165
+
166
+ ##
167
+ # :attr_reader: response
168
+ #
169
+ # The ActionDispatch::Response instance for the current response.
170
+ attr_internal_reader :response
171
+
172
+ ##
173
+ # The ActionDispatch::Request::Session instance for the current request.
174
+ # See further details in the
175
+ # {Active Controller Session guide}[https://guides.rubyonrails.org/action_controller_overview.html#session].
146
176
  delegate :session, to: "@_request"
147
- delegate :headers, :status=, :location=, :content_type=,
177
+
178
+ ##
179
+ # Delegates to ActionDispatch::Response#headers.
180
+ delegate :headers, to: "@_response"
181
+
182
+ delegate :status=, :location=, :content_type=,
148
183
  :status, :location, :content_type, :media_type, to: "@_response"
149
184
 
150
185
  def initialize
151
186
  @_request = nil
152
187
  @_response = nil
188
+ @_response_body = nil
153
189
  @_routes = nil
190
+ @_params = nil
154
191
  super
155
192
  end
156
193
 
@@ -164,17 +201,19 @@ module ActionController
164
201
 
165
202
  alias :response_code :status # :nodoc:
166
203
 
167
- # Basic url_for that can be overridden for more robust functionality.
204
+ # Basic \url_for that can be overridden for more robust functionality.
168
205
  def url_for(string)
169
206
  string
170
207
  end
171
208
 
172
209
  def response_body=(body)
173
- body = [body] unless body.nil? || body.respond_to?(:each)
174
- response.reset_body!
175
- return unless body
176
- response.body = body
177
- super
210
+ if body
211
+ body = [body] if body.is_a?(String)
212
+ response.body = body
213
+ super
214
+ else
215
+ response.reset_body!
216
+ end
178
217
  end
179
218
 
180
219
  # Tests if render or redirect has already happened.
@@ -191,9 +230,22 @@ module ActionController
191
230
  end
192
231
 
193
232
  def set_response!(response) # :nodoc:
233
+ if @_response
234
+ _, _, body = @_response
235
+ body.close if body.respond_to?(:close)
236
+ end
237
+
194
238
  @_response = response
195
239
  end
196
240
 
241
+ # Assign the response and mark it as committed. No further processing will occur.
242
+ def response=(response)
243
+ set_response!(response)
244
+
245
+ # Force `performed?` to return true:
246
+ @_response_body = true
247
+ end
248
+
197
249
  def set_request!(request) # :nodoc:
198
250
  @_request = request
199
251
  @_request.controller_instance = self
@@ -209,11 +261,6 @@ module ActionController
209
261
 
210
262
  class_attribute :middleware_stack, default: ActionController::MiddlewareStack.new
211
263
 
212
- def self.inherited(base) # :nodoc:
213
- base.middleware_stack = middleware_stack.dup
214
- super
215
- end
216
-
217
264
  class << self
218
265
  # Pushes the given Rack middleware and its arguments to the bottom of the
219
266
  # middleware stack.
@@ -222,7 +269,18 @@ module ActionController
222
269
  end
223
270
  end
224
271
 
225
- # Alias for +middleware_stack+.
272
+ # The middleware stack used by this controller.
273
+ #
274
+ # By default uses a variation of ActionDispatch::MiddlewareStack which
275
+ # allows for the following syntax:
276
+ #
277
+ # class PostsController < ApplicationController
278
+ # use AuthenticationMiddleware, except: [:index, :show]
279
+ # end
280
+ #
281
+ # Read more about {Rails middleware
282
+ # stack}[https://guides.rubyonrails.org/rails_on_rack.html#action-dispatcher-middleware-stack]
283
+ # in the guides.
226
284
  def self.middleware
227
285
  middleware_stack
228
286
  end
@@ -14,8 +14,13 @@ module ActionController
14
14
  config.action_controller.log_query_tags_around_actions = true
15
15
  config.action_controller.wrap_parameters_by_default = false
16
16
 
17
+ config.eager_load_namespaces << AbstractController
17
18
  config.eager_load_namespaces << ActionController
18
19
 
20
+ initializer "action_controller.deprecator", before: :load_environment_config do |app|
21
+ app.deprecators[:action_controller] = ActionController.deprecator
22
+ end
23
+
19
24
  initializer "action_controller.assets_config", group: :all do |app|
20
25
  app.config.action_controller.assets_dir ||= app.config.paths["public"].first
21
26
  end
@@ -37,10 +42,15 @@ module ActionController
37
42
  action_on_unpermitted_parameters = options.action_on_unpermitted_parameters
38
43
 
39
44
  if action_on_unpermitted_parameters.nil?
40
- action_on_unpermitted_parameters = (Rails.env.test? || Rails.env.development?) ? :log : false
45
+ action_on_unpermitted_parameters = Rails.env.local? ? :log : false
41
46
  end
42
47
 
43
48
  ActionController::Parameters.action_on_unpermitted_parameters = action_on_unpermitted_parameters
49
+
50
+ unless options.allow_deprecated_parameters_hash_equality.nil?
51
+ ActionController::Parameters.allow_deprecated_parameters_hash_equality =
52
+ options.allow_deprecated_parameters_hash_equality
53
+ end
44
54
  end
45
55
  end
46
56
 
@@ -71,7 +81,8 @@ module ActionController
71
81
  :permit_all_parameters,
72
82
  :action_on_unpermitted_parameters,
73
83
  :always_permitted_parameters,
74
- :wrap_parameters_by_default
84
+ :wrap_parameters_by_default,
85
+ :allow_deprecated_parameters_hash_equality
75
86
  )
76
87
 
77
88
  filtered_options.each do |k, v|
@@ -99,12 +110,6 @@ module ActionController
99
110
  end
100
111
  end
101
112
 
102
- initializer "action_controller.eager_load_actions" do
103
- ActiveSupport.on_load(:after_initialize) do
104
- ActionController::Metal.descendants.each(&:action_methods) if config.eager_load
105
- end
106
- end
107
-
108
113
  initializer "action_controller.query_log_tags" do |app|
109
114
  query_logs_tags_enabled = app.config.respond_to?(:active_record) &&
110
115
  app.config.active_record.query_log_tags_enabled &&
@@ -118,7 +123,15 @@ module ActionController
118
123
  ActiveRecord::QueryLogs.taggings.merge!(
119
124
  controller: ->(context) { context[:controller]&.controller_name },
120
125
  action: ->(context) { context[:controller]&.action_name },
121
- namespaced_controller: ->(context) { context[:controller].class.name if context[:controller] }
126
+ namespaced_controller: ->(context) {
127
+ if context[:controller]
128
+ controller_class = context[:controller].class
129
+ # based on ActionController::Metal#controller_name, but does not demodulize
130
+ unless controller_class.anonymous?
131
+ controller_class.name.delete_suffix("Controller").underscore
132
+ end
133
+ end
134
+ }
122
135
  )
123
136
  end
124
137
  end