actionpack 7.0.8.4 → 7.1.3.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 (136) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +358 -362
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/abstract_controller/base.rb +20 -11
  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 -20
  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 +17 -8
  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 +139 -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 +132 -52
  43. data/lib/action_controller/metal/url_for.rb +7 -0
  44. data/lib/action_controller/metal.rb +79 -21
  45. data/lib/action_controller/railtie.rb +22 -9
  46. data/lib/action_controller/renderer.rb +98 -65
  47. data/lib/action_controller/test_case.rb +15 -5
  48. data/lib/action_controller.rb +8 -1
  49. data/lib/action_dispatch/constants.rb +32 -0
  50. data/lib/action_dispatch/deprecator.rb +7 -0
  51. data/lib/action_dispatch/http/cache.rb +1 -3
  52. data/lib/action_dispatch/http/content_security_policy.rb +9 -8
  53. data/lib/action_dispatch/http/filter_parameters.rb +11 -5
  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 +38 -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 +80 -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 +9 -8
  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 +186 -27
  78. data/lib/action_dispatch/middleware/executor.rb +1 -1
  79. data/lib/action_dispatch/middleware/flash.rb +7 -0
  80. data/lib/action_dispatch/middleware/host_authorization.rb +6 -3
  81. data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
  82. data/lib/action_dispatch/middleware/reloader.rb +7 -5
  83. data/lib/action_dispatch/middleware/remote_ip.rb +17 -16
  84. data/lib/action_dispatch/middleware/request_id.rb +2 -0
  85. data/lib/action_dispatch/middleware/server_timing.rb +4 -4
  86. data/lib/action_dispatch/middleware/session/abstract_store.rb +5 -0
  87. data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
  88. data/lib/action_dispatch/middleware/session/cookie_store.rb +11 -5
  89. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
  90. data/lib/action_dispatch/middleware/show_exceptions.rb +19 -15
  91. data/lib/action_dispatch/middleware/ssl.rb +18 -6
  92. data/lib/action_dispatch/middleware/stack.rb +7 -2
  93. data/lib/action_dispatch/middleware/static.rb +12 -8
  94. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
  95. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +4 -4
  96. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
  97. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +7 -7
  98. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
  99. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +17 -0
  100. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +16 -12
  101. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -1
  102. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
  103. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +4 -4
  104. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  105. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
  106. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
  107. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +46 -37
  108. data/lib/action_dispatch/railtie.rb +14 -4
  109. data/lib/action_dispatch/request/session.rb +16 -6
  110. data/lib/action_dispatch/request/utils.rb +8 -3
  111. data/lib/action_dispatch/routing/inspector.rb +54 -6
  112. data/lib/action_dispatch/routing/mapper.rb +35 -24
  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 +10 -15
  117. data/lib/action_dispatch/routing/url_for.rb +5 -1
  118. data/lib/action_dispatch/routing.rb +7 -7
  119. data/lib/action_dispatch/system_test_case.rb +3 -3
  120. data/lib/action_dispatch/system_testing/browser.rb +20 -19
  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/assertion_response.rb +1 -1
  124. data/lib/action_dispatch/testing/assertions/response.rb +13 -6
  125. data/lib/action_dispatch/testing/assertions/routing.rb +67 -28
  126. data/lib/action_dispatch/testing/assertions.rb +3 -1
  127. data/lib/action_dispatch/testing/integration.rb +27 -17
  128. data/lib/action_dispatch/testing/request_encoder.rb +4 -1
  129. data/lib/action_dispatch/testing/test_process.rb +4 -3
  130. data/lib/action_dispatch/testing/test_request.rb +1 -1
  131. data/lib/action_dispatch/testing/test_response.rb +23 -9
  132. data/lib/action_dispatch.rb +37 -4
  133. data/lib/action_pack/gem_version.rb +3 -3
  134. data/lib/action_pack/version.rb +1 -1
  135. data/lib/action_pack.rb +1 -1
  136. metadata +62 -26
@@ -4,6 +4,7 @@ require "active_support/core_ext/hash/indifferent_access"
4
4
  require "active_support/core_ext/array/wrap"
5
5
  require "active_support/core_ext/string/filters"
6
6
  require "active_support/core_ext/object/to_query"
7
+ require "active_support/deep_mergeable"
7
8
  require "action_dispatch/http/upload"
8
9
  require "rack/test"
9
10
  require "stringio"
@@ -64,7 +65,14 @@ module ActionController
64
65
  end
65
66
  end
66
67
 
67
- # == Action Controller \Parameters
68
+ # Raised when initializing Parameters with keys that aren't strings or symbols.
69
+ #
70
+ # ActionController::Parameters.new(123 => 456)
71
+ # # => ActionController::InvalidParameterKey: all keys must be Strings or Symbols, got: Integer
72
+ class InvalidParameterKey < ArgumentError
73
+ end
74
+
75
+ # = Action Controller \Parameters
68
76
  #
69
77
  # Allows you to choose which attributes should be permitted for mass updating
70
78
  # and thus prevent accidentally exposing that which shouldn't be exposed.
@@ -92,8 +100,8 @@ module ActionController
92
100
  # * +permit_all_parameters+ - If it's +true+, all the parameters will be
93
101
  # permitted by default. The default is +false+.
94
102
  # * +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:
103
+ # permitted are found. The default value is <tt>:log</tt> in test and development environments,
104
+ # +false+ otherwise. The values can be:
97
105
  # * +false+ to take no action.
98
106
  # * <tt>:log</tt> to emit an <tt>ActiveSupport::Notifications.instrument</tt> event on the
99
107
  # <tt>unpermitted_parameters.action_controller</tt> topic and log at the DEBUG level.
@@ -123,17 +131,44 @@ module ActionController
123
131
  # environment they should only be set once at boot-time and never mutated at
124
132
  # runtime.
125
133
  #
126
- # You can fetch values of <tt>ActionController::Parameters</tt> using either
134
+ # You can fetch values of +ActionController::Parameters+ using either
127
135
  # <tt>:key</tt> or <tt>"key"</tt>.
128
136
  #
129
137
  # params = ActionController::Parameters.new(key: "value")
130
138
  # params[:key] # => "value"
131
139
  # params["key"] # => "value"
132
140
  class Parameters
141
+ include ActiveSupport::DeepMergeable
142
+
133
143
  cattr_accessor :permit_all_parameters, instance_accessor: false, default: false
134
144
 
135
145
  cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
136
146
 
147
+ ##
148
+ # :method: deep_merge
149
+ #
150
+ # :call-seq:
151
+ # deep_merge(other_hash, &block)
152
+ #
153
+ # Returns a new +ActionController::Parameters+ instance with +self+ and +other_hash+ merged recursively.
154
+ #
155
+ # Like with <tt>Hash#merge</tt> in the standard library, a block can be provided
156
+ # to merge values.
157
+ #
158
+ #--
159
+ # Implemented by ActiveSupport::DeepMergeable#deep_merge.
160
+
161
+ ##
162
+ # :method: deep_merge!
163
+ #
164
+ # :call-seq:
165
+ # deep_merge!(other_hash, &block)
166
+ #
167
+ # Same as +#deep_merge+, but modifies +self+.
168
+ #
169
+ #--
170
+ # Implemented by ActiveSupport::DeepMergeable#deep_merge!.
171
+
137
172
  ##
138
173
  # :method: as_json
139
174
  #
@@ -160,12 +195,12 @@ module ActionController
160
195
  # Returns true if the parameters have no key/value pairs.
161
196
 
162
197
  ##
163
- # :method: has_value?
198
+ # :method: exclude?
164
199
  #
165
200
  # :call-seq:
166
- # has_value?(value)
201
+ # exclude?(key)
167
202
  #
168
- # Returns true if the given value is present for some key in the parameters.
203
+ # Returns true if the given key is not present in the parameters.
169
204
 
170
205
  ##
171
206
  # :method: include?
@@ -191,22 +226,7 @@ module ActionController
191
226
  #
192
227
  # Returns the content of the parameters as a string.
193
228
 
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?,
229
+ delegate :keys, :empty?, :exclude?, :include?,
210
230
  :as_json, :to_s, :each_key, to: :@parameters
211
231
 
212
232
  alias_method :has_key?, :include?
@@ -222,13 +242,15 @@ module ActionController
222
242
  # config.action_controller.always_permitted_parameters = %w( controller action format )
223
243
  cattr_accessor :always_permitted_parameters, default: %w( controller action )
224
244
 
245
+ cattr_accessor :allow_deprecated_parameters_hash_equality, default: true, instance_accessor: false
246
+
225
247
  class << self
226
248
  def nested_attribute?(key, value) # :nodoc:
227
249
  /\A-?\d+\z/.match?(key) && (value.is_a?(Hash) || value.is_a?(Parameters))
228
250
  end
229
251
  end
230
252
 
231
- # Returns a new <tt>ActionController::Parameters</tt> instance.
253
+ # Returns a new +ActionController::Parameters+ instance.
232
254
  # Also, sets the +permitted+ attribute to the default value of
233
255
  # <tt>ActionController::Parameters.permit_all_parameters</tt>.
234
256
  #
@@ -245,6 +267,12 @@ module ActionController
245
267
  # params.permitted? # => true
246
268
  # Person.new(params) # => #<Person id: nil, name: "Francesco">
247
269
  def initialize(parameters = {}, logging_context = {})
270
+ parameters.each_key do |key|
271
+ unless key.is_a?(String) || key.is_a?(Symbol)
272
+ raise InvalidParameterKey, "all keys must be Strings or Symbols, got: #{key.class}"
273
+ end
274
+ end
275
+
248
276
  @parameters = parameters.with_indifferent_access
249
277
  @logging_context = logging_context
250
278
  @permitted = self.class.permit_all_parameters
@@ -256,7 +284,20 @@ module ActionController
256
284
  if other.respond_to?(:permitted?)
257
285
  permitted? == other.permitted? && parameters == other.parameters
258
286
  else
259
- @parameters == other
287
+ if self.class.allow_deprecated_parameters_hash_equality && Hash === other
288
+ ActionController.deprecator.warn <<-WARNING.squish
289
+ Comparing equality between `ActionController::Parameters` and a
290
+ `Hash` is deprecated and will be removed in Rails 7.2. Please only do
291
+ comparisons between instances of `ActionController::Parameters`. If
292
+ you need to compare to a hash, first convert it using
293
+ `ActionController::Parameters#new`.
294
+ To disable the deprecated behavior set
295
+ `Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false`.
296
+ WARNING
297
+ @parameters == other
298
+ else
299
+ super
300
+ end
260
301
  end
261
302
  end
262
303
 
@@ -282,9 +323,9 @@ module ActionController
282
323
  #
283
324
  # safe_params = params.permit(:name)
284
325
  # safe_params.to_h # => {"name"=>"Senjougahara Hitagi"}
285
- def to_h
326
+ def to_h(&block)
286
327
  if permitted?
287
- convert_parameters_to_hashes(@parameters, :to_h)
328
+ convert_parameters_to_hashes(@parameters, :to_h, &block)
288
329
  else
289
330
  raise UnfilteredParameters
290
331
  end
@@ -374,6 +415,11 @@ module ActionController
374
415
  self
375
416
  end
376
417
 
418
+ # Returns a new array of the values of the parameters.
419
+ def values
420
+ to_enum(:each_value).to_a
421
+ end
422
+
377
423
  # Attribute that keeps track of converted arrays, if any, to avoid double
378
424
  # looping in the common use case permit + mass-assignment. Defined in a
379
425
  # method to instantiate it only if needed.
@@ -480,7 +526,7 @@ module ActionController
480
526
 
481
527
  alias :required :require
482
528
 
483
- # Returns a new <tt>ActionController::Parameters</tt> instance that
529
+ # Returns a new +ActionController::Parameters+ instance that
484
530
  # includes only the given +filters+ and sets the +permitted+ attribute
485
531
  # for the object to +true+. This is useful for limiting which attributes
486
532
  # should be allowed for mass updating.
@@ -665,7 +711,7 @@ module ActionController
665
711
  @parameters.dig(*keys)
666
712
  end
667
713
 
668
- # Returns a new <tt>ActionController::Parameters</tt> instance that
714
+ # Returns a new +ActionController::Parameters+ instance that
669
715
  # includes only the given +keys+. If the given +keys+
670
716
  # don't exist, returns an empty hash.
671
717
  #
@@ -676,14 +722,14 @@ module ActionController
676
722
  new_instance_with_inherited_permitted_status(@parameters.slice(*keys))
677
723
  end
678
724
 
679
- # Returns the current <tt>ActionController::Parameters</tt> instance which
725
+ # Returns the current +ActionController::Parameters+ instance which
680
726
  # contains only the given +keys+.
681
727
  def slice!(*keys)
682
728
  @parameters.slice!(*keys)
683
729
  self
684
730
  end
685
731
 
686
- # Returns a new <tt>ActionController::Parameters</tt> instance that
732
+ # Returns a new +ActionController::Parameters+ instance that
687
733
  # filters out the given +keys+.
688
734
  #
689
735
  # params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
@@ -692,6 +738,7 @@ module ActionController
692
738
  def except(*keys)
693
739
  new_instance_with_inherited_permitted_status(@parameters.except(*keys))
694
740
  end
741
+ alias_method :without, :except
695
742
 
696
743
  # Removes and returns the key/value pairs matching the given keys.
697
744
  #
@@ -702,7 +749,7 @@ module ActionController
702
749
  new_instance_with_inherited_permitted_status(@parameters.extract!(*keys))
703
750
  end
704
751
 
705
- # Returns a new <tt>ActionController::Parameters</tt> instance with the results of
752
+ # Returns a new +ActionController::Parameters+ instance with the results of
706
753
  # running +block+ once for every value. The keys are unchanged.
707
754
  #
708
755
  # params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
@@ -716,14 +763,14 @@ module ActionController
716
763
  end
717
764
 
718
765
  # Performs values transformation and returns the altered
719
- # <tt>ActionController::Parameters</tt> instance.
766
+ # +ActionController::Parameters+ instance.
720
767
  def transform_values!
721
768
  return to_enum(:transform_values!) unless block_given?
722
769
  @parameters.transform_values! { |v| yield convert_value_to_parameters(v) }
723
770
  self
724
771
  end
725
772
 
726
- # Returns a new <tt>ActionController::Parameters</tt> instance with the
773
+ # Returns a new +ActionController::Parameters+ instance with the
727
774
  # results of running +block+ once for every key. The values are unchanged.
728
775
  def transform_keys(&block)
729
776
  return to_enum(:transform_keys) unless block_given?
@@ -733,14 +780,14 @@ module ActionController
733
780
  end
734
781
 
735
782
  # Performs keys transformation and returns the altered
736
- # <tt>ActionController::Parameters</tt> instance.
783
+ # +ActionController::Parameters+ instance.
737
784
  def transform_keys!(&block)
738
785
  return to_enum(:transform_keys!) unless block_given?
739
786
  @parameters.transform_keys!(&block)
740
787
  self
741
788
  end
742
789
 
743
- # Returns a new <tt>ActionController::Parameters</tt> instance with the
790
+ # Returns a new +ActionController::Parameters+ instance with the
744
791
  # results of running +block+ once for every key. This includes the keys
745
792
  # from the root hash and from all nested hashes and arrays. The values are unchanged.
746
793
  def deep_transform_keys(&block)
@@ -749,7 +796,7 @@ module ActionController
749
796
  )
750
797
  end
751
798
 
752
- # Returns the same <tt>ActionController::Parameters</tt> instance with
799
+ # Returns the same +ActionController::Parameters+ instance with
753
800
  # changed keys. This includes the keys from the root hash and from all
754
801
  # nested hashes and arrays. The values are unchanged.
755
802
  def deep_transform_keys!(&block)
@@ -765,7 +812,7 @@ module ActionController
765
812
  convert_value_to_parameters(@parameters.delete(key, &block))
766
813
  end
767
814
 
768
- # Returns a new <tt>ActionController::Parameters</tt> instance with only
815
+ # Returns a new +ActionController::Parameters+ instance with only
769
816
  # items that the block evaluates to true.
770
817
  def select(&block)
771
818
  new_instance_with_inherited_permitted_status(@parameters.select(&block))
@@ -778,7 +825,7 @@ module ActionController
778
825
  end
779
826
  alias_method :keep_if, :select!
780
827
 
781
- # Returns a new <tt>ActionController::Parameters</tt> instance with items
828
+ # Returns a new +ActionController::Parameters+ instance with items
782
829
  # that the block evaluates to true removed.
783
830
  def reject(&block)
784
831
  new_instance_with_inherited_permitted_status(@parameters.reject(&block))
@@ -791,7 +838,7 @@ module ActionController
791
838
  end
792
839
  alias_method :delete_if, :reject!
793
840
 
794
- # Returns a new <tt>ActionController::Parameters</tt> instance with +nil+ values removed.
841
+ # Returns a new +ActionController::Parameters+ instance with +nil+ values removed.
795
842
  def compact
796
843
  new_instance_with_inherited_permitted_status(@parameters.compact)
797
844
  end
@@ -801,7 +848,7 @@ module ActionController
801
848
  self if @parameters.compact!
802
849
  end
803
850
 
804
- # Returns a new <tt>ActionController::Parameters</tt> instance without the blank values.
851
+ # Returns a new +ActionController::Parameters+ instance without the blank values.
805
852
  # Uses Object#blank? for determining if a value is blank.
806
853
  def compact_blank
807
854
  reject { |_k, v| v.blank? }
@@ -813,13 +860,20 @@ module ActionController
813
860
  reject! { |_k, v| v.blank? }
814
861
  end
815
862
 
863
+ # Returns true if the given value is present for some key in the parameters.
864
+ def has_value?(value)
865
+ each_value.include?(convert_value_to_parameters(value))
866
+ end
867
+
868
+ alias value? has_value?
869
+
816
870
  # Returns values that were assigned to the given +keys+. Note that all the
817
- # +Hash+ objects will be converted to <tt>ActionController::Parameters</tt>.
871
+ # +Hash+ objects will be converted to +ActionController::Parameters+.
818
872
  def values_at(*keys)
819
873
  convert_value_to_parameters(@parameters.values_at(*keys))
820
874
  end
821
875
 
822
- # Returns a new <tt>ActionController::Parameters</tt> instance with all keys from
876
+ # Returns a new +ActionController::Parameters+ instance with all keys from
823
877
  # +other_hash+ merged into current hash.
824
878
  def merge(other_hash)
825
879
  new_instance_with_inherited_permitted_status(
@@ -827,14 +881,21 @@ module ActionController
827
881
  )
828
882
  end
829
883
 
830
- # Returns the current <tt>ActionController::Parameters</tt> instance with
884
+ ##
885
+ # :call-seq: merge!(other_hash)
886
+ #
887
+ # Returns the current +ActionController::Parameters+ instance with
831
888
  # +other_hash+ merged into current hash.
832
- def merge!(other_hash)
833
- @parameters.merge!(other_hash.to_h)
889
+ def merge!(other_hash, &block)
890
+ @parameters.merge!(other_hash.to_h, &block)
834
891
  self
835
892
  end
836
893
 
837
- # Returns a new <tt>ActionController::Parameters</tt> instance with all keys
894
+ def deep_merge?(other_hash) # :nodoc:
895
+ other_hash.is_a?(ActiveSupport::DeepMergeable)
896
+ end
897
+
898
+ # Returns a new +ActionController::Parameters+ instance with all keys
838
899
  # from current hash merged into +other_hash+.
839
900
  def reverse_merge(other_hash)
840
901
  new_instance_with_inherited_permitted_status(
@@ -843,7 +904,7 @@ module ActionController
843
904
  end
844
905
  alias_method :with_defaults, :reverse_merge
845
906
 
846
- # Returns the current <tt>ActionController::Parameters</tt> instance with
907
+ # Returns the current +ActionController::Parameters+ instance with
847
908
  # current hash merged into +other_hash+.
848
909
  def reverse_merge!(other_hash)
849
910
  @parameters.merge!(other_hash.to_h) { |key, left, right| left }
@@ -900,6 +961,22 @@ module ActionController
900
961
  end
901
962
  end
902
963
 
964
+ # Returns parameter value for the given +key+ separated by +delimiter+.
965
+ #
966
+ # params = ActionController::Parameters.new(id: "1_123", tags: "ruby,rails")
967
+ # params.extract_value(:id) # => ["1", "123"]
968
+ # params.extract_value(:tags, delimiter: ",") # => ["ruby", "rails"]
969
+ # params.extract_value(:non_existent_key) # => nil
970
+ #
971
+ # Note that if the given +key+'s value contains blank elements, then
972
+ # the returned array will include empty strings.
973
+ #
974
+ # params = ActionController::Parameters.new(tags: "ruby,rails,,web")
975
+ # params.extract_value(:tags) # => ["ruby", "rails", "", "web"]
976
+ def extract_value(key, delimiter: "_")
977
+ @parameters[key]&.split(delimiter, -1)
978
+ end
979
+
903
980
  protected
904
981
  attr_reader :parameters
905
982
 
@@ -922,14 +999,15 @@ module ActionController
922
999
  end
923
1000
  end
924
1001
 
925
- def convert_parameters_to_hashes(value, using)
1002
+ def convert_parameters_to_hashes(value, using, &block)
926
1003
  case value
927
1004
  when Array
928
1005
  value.map { |v| convert_parameters_to_hashes(v, using) }
929
1006
  when Hash
930
- value.transform_values do |v|
1007
+ transformed = value.transform_values do |v|
931
1008
  convert_parameters_to_hashes(v, using)
932
- end.with_indifferent_access
1009
+ end
1010
+ (block_given? ? transformed.to_h(&block) : transformed).with_indifferent_access
933
1011
  when Parameters
934
1012
  value.send(using)
935
1013
  else
@@ -1112,6 +1190,8 @@ module ActionController
1112
1190
  case element
1113
1191
  when ->(e) { permitted_scalar?(e) }
1114
1192
  sanitized << element
1193
+ when Array
1194
+ sanitized << permit_any_in_array(element)
1115
1195
  when Parameters
1116
1196
  sanitized << permit_any_in_parameters(element)
1117
1197
  else
@@ -1127,7 +1207,7 @@ module ActionController
1127
1207
  end
1128
1208
  end
1129
1209
 
1130
- # == Strong \Parameters
1210
+ # = Strong \Parameters
1131
1211
  #
1132
1212
  # It provides an interface for protecting attributes from end-user
1133
1213
  # 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