actionpack 6.1.7 → 7.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +251 -406
- data/MIT-LICENSE +1 -0
- data/README.rdoc +2 -3
- data/lib/abstract_controller/asset_paths.rb +1 -1
- data/lib/abstract_controller/base.rb +13 -26
- data/lib/abstract_controller/caching/fragments.rb +2 -2
- data/lib/abstract_controller/caching.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +21 -7
- data/lib/abstract_controller/collector.rb +2 -2
- data/lib/abstract_controller/error.rb +1 -1
- data/lib/abstract_controller/helpers.rb +4 -3
- data/lib/abstract_controller/logger.rb +1 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/translation.rb +3 -2
- data/lib/abstract_controller/url_for.rb +4 -6
- data/lib/action_controller/api.rb +6 -6
- data/lib/action_controller/base.rb +5 -4
- data/lib/action_controller/form_builder.rb +2 -2
- data/lib/action_controller/log_subscriber.rb +4 -3
- data/lib/action_controller/metal/conditional_get.rb +39 -2
- data/lib/action_controller/metal/content_security_policy.rb +36 -2
- data/lib/action_controller/metal/cookies.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +5 -13
- data/lib/action_controller/metal/exceptions.rb +19 -30
- data/lib/action_controller/metal/flash.rb +6 -2
- data/lib/action_controller/metal/helpers.rb +2 -2
- data/lib/action_controller/metal/http_authentication.rb +66 -39
- data/lib/action_controller/metal/instrumentation.rb +57 -52
- data/lib/action_controller/metal/live.rb +43 -2
- data/lib/action_controller/metal/mime_responds.rb +3 -3
- data/lib/action_controller/metal/params_wrapper.rb +20 -11
- data/lib/action_controller/metal/permissions_policy.rb +19 -28
- data/lib/action_controller/metal/redirecting.rb +89 -18
- data/lib/action_controller/metal/renderers.rb +10 -11
- data/lib/action_controller/metal/rendering.rb +8 -8
- data/lib/action_controller/metal/request_forgery_protection.rb +78 -29
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/streaming.rb +6 -8
- data/lib/action_controller/metal/strong_parameters.rb +100 -54
- data/lib/action_controller/metal/testing.rb +9 -2
- data/lib/action_controller/metal/url_for.rb +3 -3
- data/lib/action_controller/metal.rb +10 -13
- data/lib/action_controller/railtie.rb +49 -6
- data/lib/action_controller/renderer.rb +1 -1
- data/lib/action_controller/test_case.rb +28 -7
- data/lib/action_controller.rb +2 -5
- data/lib/action_dispatch/http/cache.rb +13 -6
- data/lib/action_dispatch/http/content_security_policy.rb +108 -35
- data/lib/action_dispatch/http/filter_parameters.rb +5 -0
- data/lib/action_dispatch/http/mime_negotiation.rb +15 -5
- data/lib/action_dispatch/http/mime_type.rb +9 -11
- data/lib/action_dispatch/http/parameters.rb +5 -5
- data/lib/action_dispatch/http/permissions_policy.rb +17 -1
- data/lib/action_dispatch/http/request.rb +12 -21
- data/lib/action_dispatch/http/response.rb +3 -16
- data/lib/action_dispatch/http/url.rb +11 -19
- data/lib/action_dispatch/journey/gtg/builder.rb +11 -12
- data/lib/action_dispatch/journey/gtg/simulator.rb +10 -4
- data/lib/action_dispatch/journey/gtg/transition_table.rb +77 -21
- data/lib/action_dispatch/journey/nodes/node.rb +70 -5
- data/lib/action_dispatch/journey/path/pattern.rb +22 -13
- data/lib/action_dispatch/journey/route.rb +6 -13
- data/lib/action_dispatch/journey/router/utils.rb +2 -2
- data/lib/action_dispatch/journey/router.rb +1 -1
- data/lib/action_dispatch/journey/routes.rb +3 -3
- data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
- data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +0 -1
- data/lib/action_dispatch/middleware/cookies.rb +14 -7
- data/lib/action_dispatch/middleware/debug_exceptions.rb +6 -4
- data/lib/action_dispatch/middleware/debug_locks.rb +3 -3
- data/lib/action_dispatch/middleware/exception_wrapper.rb +4 -0
- data/lib/action_dispatch/middleware/executor.rb +3 -0
- data/lib/action_dispatch/middleware/flash.rb +17 -18
- data/lib/action_dispatch/middleware/host_authorization.rb +1 -12
- data/lib/action_dispatch/middleware/remote_ip.rb +16 -4
- data/lib/action_dispatch/middleware/request_id.rb +1 -1
- data/lib/action_dispatch/middleware/server_timing.rb +76 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +1 -1
- data/lib/action_dispatch/middleware/session/cookie_store.rb +9 -9
- data/lib/action_dispatch/middleware/show_exceptions.rb +7 -9
- data/lib/action_dispatch/middleware/stack.rb +27 -9
- data/lib/action_dispatch/middleware/static.rb +2 -6
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -11
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +3 -2
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +2 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +28 -18
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +5 -14
- data/lib/action_dispatch/railtie.rb +8 -2
- data/lib/action_dispatch/request/session.rb +43 -13
- data/lib/action_dispatch/routing/inspector.rb +1 -1
- data/lib/action_dispatch/routing/mapper.rb +59 -83
- data/lib/action_dispatch/routing/redirection.rb +5 -2
- data/lib/action_dispatch/routing/route_set.rb +17 -7
- data/lib/action_dispatch/routing/routes_proxy.rb +1 -1
- data/lib/action_dispatch/routing/url_for.rb +4 -5
- data/lib/action_dispatch/routing.rb +5 -6
- data/lib/action_dispatch/system_test_case.rb +5 -5
- data/lib/action_dispatch/system_testing/browser.rb +2 -12
- data/lib/action_dispatch/system_testing/driver.rb +35 -11
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +11 -7
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +0 -8
- data/lib/action_dispatch/testing/assertions/routing.rb +3 -2
- data/lib/action_dispatch/testing/assertions.rb +2 -5
- data/lib/action_dispatch/testing/integration.rb +6 -8
- data/lib/action_dispatch/testing/test_process.rb +3 -29
- data/lib/action_dispatch/testing/test_response.rb +20 -2
- data/lib/action_dispatch.rb +1 -0
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack/version.rb +1 -1
- metadata +14 -13
@@ -27,28 +27,13 @@ module ActionController
|
|
27
27
|
super("param is missing or the value is empty: #{param}")
|
28
28
|
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
@error = error
|
33
|
-
end
|
34
|
-
|
35
|
-
def corrections
|
36
|
-
if @error.param && @error.keys
|
37
|
-
maybe_these = @error.keys
|
30
|
+
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
31
|
+
include DidYouMean::Correctable # :nodoc:
|
38
32
|
|
39
|
-
|
40
|
-
|
41
|
-
}.reverse.first(4)
|
42
|
-
else
|
43
|
-
[]
|
44
|
-
end
|
33
|
+
def corrections # :nodoc:
|
34
|
+
@corrections ||= DidYouMean::SpellChecker.new(dictionary: keys).correct(param.to_s)
|
45
35
|
end
|
46
36
|
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
|
52
37
|
end
|
53
38
|
|
54
39
|
# Raised when a supplied parameter is not expected and
|
@@ -96,7 +81,7 @@ module ActionController
|
|
96
81
|
# })
|
97
82
|
#
|
98
83
|
# permitted = params.require(:person).permit(:name, :age)
|
99
|
-
# permitted # =>
|
84
|
+
# permitted # => #<ActionController::Parameters {"name"=>"Francesco", "age"=>22} permitted: true>
|
100
85
|
# permitted.permitted? # => true
|
101
86
|
#
|
102
87
|
# Person.first.update!(permitted)
|
@@ -106,11 +91,13 @@ module ActionController
|
|
106
91
|
#
|
107
92
|
# * +permit_all_parameters+ - If it's +true+, all the parameters will be
|
108
93
|
# permitted by default. The default is +false+.
|
109
|
-
# * +action_on_unpermitted_parameters+ -
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
#
|
94
|
+
# * +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:
|
97
|
+
# * +false+ to take no action.
|
98
|
+
# * <tt>:log</tt> to emit an <tt>ActiveSupport::Notifications.instrument</tt> event on the
|
99
|
+
# <tt>unpermitted_parameters.action_controller</tt> topic and log at the DEBUG level.
|
100
|
+
# * <tt>:raise</tt> to raise a <tt>ActionController::UnpermittedParameters</tt> exception.
|
114
101
|
#
|
115
102
|
# Examples:
|
116
103
|
#
|
@@ -124,7 +111,7 @@ module ActionController
|
|
124
111
|
#
|
125
112
|
# params = ActionController::Parameters.new(a: "123", b: "456")
|
126
113
|
# params.permit(:c)
|
127
|
-
# # =>
|
114
|
+
# # => #<ActionController::Parameters {} permitted: true>
|
128
115
|
#
|
129
116
|
# ActionController::Parameters.action_on_unpermitted_parameters = :raise
|
130
117
|
#
|
@@ -249,7 +236,7 @@ module ActionController
|
|
249
236
|
# By default, never raise an UnpermittedParameters exception if these
|
250
237
|
# params are present. The default includes both 'controller' and 'action'
|
251
238
|
# because they are added by Rails and should be of no concern. One way
|
252
|
-
# to change these is to specify
|
239
|
+
# to change these is to specify +always_permitted_parameters+ in your
|
253
240
|
# config. For instance:
|
254
241
|
#
|
255
242
|
# config.action_controller.always_permitted_parameters = %w( controller action format )
|
@@ -277,8 +264,9 @@ module ActionController
|
|
277
264
|
# params = ActionController::Parameters.new(name: "Francesco")
|
278
265
|
# params.permitted? # => true
|
279
266
|
# Person.new(params) # => #<Person id: nil, name: "Francesco">
|
280
|
-
def initialize(parameters = {})
|
267
|
+
def initialize(parameters = {}, logging_context = {})
|
281
268
|
@parameters = parameters.with_indifferent_access
|
269
|
+
@logging_context = logging_context
|
282
270
|
@permitted = self.class.permit_all_parameters
|
283
271
|
end
|
284
272
|
|
@@ -291,10 +279,15 @@ module ActionController
|
|
291
279
|
@parameters == other
|
292
280
|
end
|
293
281
|
end
|
294
|
-
|
282
|
+
|
283
|
+
def eql?(other)
|
284
|
+
self.class == other.class &&
|
285
|
+
permitted? == other.permitted? &&
|
286
|
+
parameters.eql?(other.parameters)
|
287
|
+
end
|
295
288
|
|
296
289
|
def hash
|
297
|
-
[@parameters
|
290
|
+
[self.class, @parameters, @permitted].hash
|
298
291
|
end
|
299
292
|
|
300
293
|
# Returns a safe <tt>ActiveSupport::HashWithIndifferentAccess</tt>
|
@@ -454,7 +447,7 @@ module ActionController
|
|
454
447
|
# either present or the singleton +false+, returns said value:
|
455
448
|
#
|
456
449
|
# ActionController::Parameters.new(person: { name: "Francesco" }).require(:person)
|
457
|
-
# # =>
|
450
|
+
# # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
458
451
|
#
|
459
452
|
# Otherwise raises <tt>ActionController::ParameterMissing</tt>:
|
460
453
|
#
|
@@ -582,13 +575,48 @@ module ActionController
|
|
582
575
|
# })
|
583
576
|
#
|
584
577
|
# params.require(:person).permit(:contact)
|
585
|
-
# # =>
|
578
|
+
# # => #<ActionController::Parameters {} permitted: true>
|
586
579
|
#
|
587
580
|
# params.require(:person).permit(contact: :phone)
|
588
|
-
# # =>
|
581
|
+
# # => #<ActionController::Parameters {"contact"=>#<ActionController::Parameters {"phone"=>"555-1234"} permitted: true>} permitted: true>
|
589
582
|
#
|
590
583
|
# params.require(:person).permit(contact: [ :email, :phone ])
|
591
|
-
# # =>
|
584
|
+
# # => #<ActionController::Parameters {"contact"=>#<ActionController::Parameters {"email"=>"none@test.com", "phone"=>"555-1234"} permitted: true>} permitted: true>
|
585
|
+
#
|
586
|
+
# If your parameters specify multiple parameters indexed by a number,
|
587
|
+
# you can permit each set of parameters under the numeric key to be the same using the same syntax as permitting a single item.
|
588
|
+
#
|
589
|
+
# params = ActionController::Parameters.new({
|
590
|
+
# person: {
|
591
|
+
# '0': {
|
592
|
+
# email: "none@test.com",
|
593
|
+
# phone: "555-1234"
|
594
|
+
# },
|
595
|
+
# '1': {
|
596
|
+
# email: "nothing@test.com",
|
597
|
+
# phone: "555-6789"
|
598
|
+
# },
|
599
|
+
# }
|
600
|
+
# })
|
601
|
+
# params.permit(person: [:email]).to_h
|
602
|
+
# # => {"person"=>{"0"=>{"email"=>"none@test.com"}, "1"=>{"email"=>"nothing@test.com"}}}
|
603
|
+
#
|
604
|
+
# If you want to specify what keys you want from each numeric key, you can instead specify each one individually
|
605
|
+
#
|
606
|
+
# params = ActionController::Parameters.new({
|
607
|
+
# person: {
|
608
|
+
# '0': {
|
609
|
+
# email: "none@test.com",
|
610
|
+
# phone: "555-1234"
|
611
|
+
# },
|
612
|
+
# '1': {
|
613
|
+
# email: "nothing@test.com",
|
614
|
+
# phone: "555-6789"
|
615
|
+
# },
|
616
|
+
# }
|
617
|
+
# })
|
618
|
+
# params.permit(person: { '0': [:email], '1': [:phone]}).to_h
|
619
|
+
# # => {"person"=>{"0"=>{"email"=>"none@test.com"}, "1"=>{"phone"=>"555-6789"}}}
|
592
620
|
def permit(*filters)
|
593
621
|
params = self.class.new
|
594
622
|
|
@@ -610,7 +638,7 @@ module ActionController
|
|
610
638
|
# returns +nil+.
|
611
639
|
#
|
612
640
|
# params = ActionController::Parameters.new(person: { name: "Francesco" })
|
613
|
-
# params[:person] # =>
|
641
|
+
# params[:person] # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
614
642
|
# params[:none] # => nil
|
615
643
|
def [](key)
|
616
644
|
convert_hashes_to_parameters(key, @parameters[key])
|
@@ -630,9 +658,9 @@ module ActionController
|
|
630
658
|
# is given, then that will be run and its result returned.
|
631
659
|
#
|
632
660
|
# params = ActionController::Parameters.new(person: { name: "Francesco" })
|
633
|
-
# params.fetch(:person) # =>
|
661
|
+
# params.fetch(:person) # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
634
662
|
# params.fetch(:none) # => ActionController::ParameterMissing: param is missing or the value is empty: none
|
635
|
-
# params.fetch(:none, {}) # =>
|
663
|
+
# params.fetch(:none, {}) # => #<ActionController::Parameters {} permitted: false>
|
636
664
|
# params.fetch(:none, "Francesco") # => "Francesco"
|
637
665
|
# params.fetch(:none) { "Francesco" } # => "Francesco"
|
638
666
|
def fetch(key, *args)
|
@@ -666,8 +694,8 @@ module ActionController
|
|
666
694
|
# don't exist, returns an empty hash.
|
667
695
|
#
|
668
696
|
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
669
|
-
# params.slice(:a, :b) # =>
|
670
|
-
# params.slice(:d) # =>
|
697
|
+
# params.slice(:a, :b) # => #<ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
|
698
|
+
# params.slice(:d) # => #<ActionController::Parameters {} permitted: false>
|
671
699
|
def slice(*keys)
|
672
700
|
new_instance_with_inherited_permitted_status(@parameters.slice(*keys))
|
673
701
|
end
|
@@ -683,8 +711,8 @@ module ActionController
|
|
683
711
|
# filters out the given +keys+.
|
684
712
|
#
|
685
713
|
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
686
|
-
# params.except(:a, :b) # =>
|
687
|
-
# params.except(:d) # =>
|
714
|
+
# params.except(:a, :b) # => #<ActionController::Parameters {"c"=>3} permitted: false>
|
715
|
+
# params.except(:d) # => #<ActionController::Parameters {"a"=>1, "b"=>2, "c"=>3} permitted: false>
|
688
716
|
def except(*keys)
|
689
717
|
new_instance_with_inherited_permitted_status(@parameters.except(*keys))
|
690
718
|
end
|
@@ -692,8 +720,8 @@ module ActionController
|
|
692
720
|
# Removes and returns the key/value pairs matching the given keys.
|
693
721
|
#
|
694
722
|
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
695
|
-
# params.extract!(:a, :b) # =>
|
696
|
-
# params # =>
|
723
|
+
# params.extract!(:a, :b) # => #<ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
|
724
|
+
# params # => #<ActionController::Parameters {"c"=>3} permitted: false>
|
697
725
|
def extract!(*keys)
|
698
726
|
new_instance_with_inherited_permitted_status(@parameters.extract!(*keys))
|
699
727
|
end
|
@@ -703,7 +731,7 @@ module ActionController
|
|
703
731
|
#
|
704
732
|
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
705
733
|
# params.transform_values { |x| x * 2 }
|
706
|
-
# # =>
|
734
|
+
# # => #<ActionController::Parameters {"a"=>2, "b"=>4, "c"=>6} permitted: false>
|
707
735
|
def transform_values
|
708
736
|
return to_enum(:transform_values) unless block_given?
|
709
737
|
new_instance_with_inherited_permitted_status(
|
@@ -755,7 +783,7 @@ module ActionController
|
|
755
783
|
|
756
784
|
# Deletes a key-value pair from +Parameters+ and returns the value. If
|
757
785
|
# +key+ is not found, returns +nil+ (or, with optional code block, yields
|
758
|
-
# +key+ and returns the result). Cf.
|
786
|
+
# +key+ and returns the result). Cf. #extract!, which returns the
|
759
787
|
# corresponding +ActionController::Parameters+ object.
|
760
788
|
def delete(key, &block)
|
761
789
|
convert_value_to_parameters(@parameters.delete(key, &block))
|
@@ -885,9 +913,13 @@ module ActionController
|
|
885
913
|
end
|
886
914
|
end
|
887
915
|
|
916
|
+
def encode_with(coder) # :nodoc:
|
917
|
+
coder.map = { "parameters" => @parameters, "permitted" => @permitted }
|
918
|
+
end
|
919
|
+
|
888
920
|
# Returns duplicate of object including all parameters.
|
889
921
|
def deep_dup
|
890
|
-
self.class.new(@parameters.deep_dup).tap do |duplicate|
|
922
|
+
self.class.new(@parameters.deep_dup, @logging_context).tap do |duplicate|
|
891
923
|
duplicate.permitted = @permitted
|
892
924
|
end
|
893
925
|
end
|
@@ -909,7 +941,7 @@ module ActionController
|
|
909
941
|
|
910
942
|
private
|
911
943
|
def new_instance_with_inherited_permitted_status(hash)
|
912
|
-
self.class.new(hash).tap do |new_instance|
|
944
|
+
self.class.new(hash, @logging_context).tap do |new_instance|
|
913
945
|
new_instance.permitted = @permitted
|
914
946
|
end
|
915
947
|
end
|
@@ -943,18 +975,24 @@ module ActionController
|
|
943
975
|
converted_arrays << converted.dup
|
944
976
|
converted
|
945
977
|
when Hash
|
946
|
-
self.class.new(value)
|
978
|
+
self.class.new(value, @logging_context)
|
947
979
|
else
|
948
980
|
value
|
949
981
|
end
|
950
982
|
end
|
951
983
|
|
952
|
-
def
|
984
|
+
def specify_numeric_keys?(filter)
|
985
|
+
if filter.respond_to?(:keys)
|
986
|
+
filter.keys.any? { |key| /\A-?\d+\z/.match?(key) }
|
987
|
+
end
|
988
|
+
end
|
989
|
+
|
990
|
+
def each_element(object, filter, &block)
|
953
991
|
case object
|
954
992
|
when Array
|
955
|
-
object.grep(Parameters).
|
993
|
+
object.grep(Parameters).filter_map(&block)
|
956
994
|
when Parameters
|
957
|
-
if object.nested_attributes?
|
995
|
+
if object.nested_attributes? && !specify_numeric_keys?(filter)
|
958
996
|
object.each_nested_attribute(&block)
|
959
997
|
else
|
960
998
|
yield object
|
@@ -968,7 +1006,7 @@ module ActionController
|
|
968
1006
|
case self.class.action_on_unpermitted_parameters
|
969
1007
|
when :log
|
970
1008
|
name = "unpermitted_parameters.action_controller"
|
971
|
-
ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys)
|
1009
|
+
ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys, context: @logging_context)
|
972
1010
|
when :raise
|
973
1011
|
raise ActionController::UnpermittedParameters.new(unpermitted_keys)
|
974
1012
|
end
|
@@ -1067,7 +1105,7 @@ module ActionController
|
|
1067
1105
|
end
|
1068
1106
|
elsif non_scalar?(value)
|
1069
1107
|
# Declaration { user: :name } or { user: [:name, :age, { address: ... }] }.
|
1070
|
-
params[key] = each_element(value) do |element|
|
1108
|
+
params[key] = each_element(value, filter[key]) do |element|
|
1071
1109
|
element.permit(*Array.wrap(filter[key]))
|
1072
1110
|
end
|
1073
1111
|
end
|
@@ -1184,7 +1222,15 @@ module ActionController
|
|
1184
1222
|
# Returns a new ActionController::Parameters object that
|
1185
1223
|
# has been instantiated with the <tt>request.parameters</tt>.
|
1186
1224
|
def params
|
1187
|
-
@_params ||=
|
1225
|
+
@_params ||= begin
|
1226
|
+
context = {
|
1227
|
+
controller: self.class.name,
|
1228
|
+
action: action_name,
|
1229
|
+
request: request,
|
1230
|
+
params: request.filtered_parameters
|
1231
|
+
}
|
1232
|
+
Parameters.new(request.parameters, context)
|
1233
|
+
end
|
1188
1234
|
end
|
1189
1235
|
|
1190
1236
|
# Assigns the given +value+ to the +params+ hash. If +value+
|
@@ -2,10 +2,17 @@
|
|
2
2
|
|
3
3
|
module ActionController
|
4
4
|
module Testing
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
|
7
5
|
# Behavior specific to functional tests
|
8
6
|
module Functional # :nodoc:
|
7
|
+
def clear_instance_variables_between_requests
|
8
|
+
if defined?(@_ivars)
|
9
|
+
new_ivars = instance_variables - @_ivars
|
10
|
+
new_ivars.each { |ivar| remove_instance_variable(ivar) }
|
11
|
+
end
|
12
|
+
|
13
|
+
@_ivars = instance_variables
|
14
|
+
end
|
15
|
+
|
9
16
|
def recycle!
|
10
17
|
@_url_options = nil
|
11
18
|
self.formats = nil
|
@@ -4,11 +4,11 @@ module ActionController
|
|
4
4
|
# Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing
|
5
5
|
# the <tt>_routes</tt> method. Otherwise, an exception will be raised.
|
6
6
|
#
|
7
|
-
# In addition to
|
7
|
+
# In addition to AbstractController::UrlFor, this module accesses the HTTP layer to define
|
8
8
|
# URL options like the +host+. In order to do so, this module requires the host class
|
9
9
|
# to implement +env+ which needs to be Rack-compatible and +request+
|
10
|
-
# which is either an instance of
|
11
|
-
# that responds to the +host+, +optional_port+, +protocol
|
10
|
+
# which is either an instance of ActionDispatch::Request or an object
|
11
|
+
# that responds to the +host+, +optional_port+, +protocol+, and
|
12
12
|
# +symbolized_path_parameter+ methods.
|
13
13
|
#
|
14
14
|
# class RootUrl
|
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
require "active_support/core_ext/array/extract_options"
|
4
4
|
require "action_dispatch/middleware/stack"
|
5
|
-
require "action_dispatch/http/request"
|
6
|
-
require "action_dispatch/http/response"
|
7
5
|
|
8
6
|
module ActionController
|
9
7
|
# Extend ActionDispatch middleware stack to make it aware of options
|
@@ -13,8 +11,8 @@ module ActionController
|
|
13
11
|
# use AuthenticationMiddleware, except: [:index, :show]
|
14
12
|
# end
|
15
13
|
#
|
16
|
-
class MiddlewareStack < ActionDispatch::MiddlewareStack
|
17
|
-
class Middleware < ActionDispatch::MiddlewareStack::Middleware
|
14
|
+
class MiddlewareStack < ActionDispatch::MiddlewareStack # :nodoc:
|
15
|
+
class Middleware < ActionDispatch::MiddlewareStack::Middleware # :nodoc:
|
18
16
|
def initialize(klass, args, actions, strategy, block)
|
19
17
|
@actions = actions
|
20
18
|
@strategy = strategy
|
@@ -62,7 +60,7 @@ module ActionController
|
|
62
60
|
|
63
61
|
# <tt>ActionController::Metal</tt> is the simplest possible controller, providing a
|
64
62
|
# valid Rack interface without the additional niceties provided by
|
65
|
-
#
|
63
|
+
# ActionController::Base.
|
66
64
|
#
|
67
65
|
# A sample metal controller might look like this:
|
68
66
|
#
|
@@ -113,7 +111,7 @@ module ActionController
|
|
113
111
|
#
|
114
112
|
# == Other Helpers
|
115
113
|
#
|
116
|
-
# You can refer to the modules included in
|
114
|
+
# You can refer to the modules included in ActionController::Base to see
|
117
115
|
# other features you can bring into your metal controller.
|
118
116
|
#
|
119
117
|
class Metal < AbstractController::Base
|
@@ -139,7 +137,7 @@ module ActionController
|
|
139
137
|
false
|
140
138
|
end
|
141
139
|
|
142
|
-
# Delegates to the class'
|
140
|
+
# Delegates to the class's ::controller_name.
|
143
141
|
def controller_name
|
144
142
|
self.class.controller_name
|
145
143
|
end
|
@@ -184,7 +182,7 @@ module ActionController
|
|
184
182
|
response_body || response.committed?
|
185
183
|
end
|
186
184
|
|
187
|
-
def dispatch(name, request, response)
|
185
|
+
def dispatch(name, request, response) # :nodoc:
|
188
186
|
set_request!(request)
|
189
187
|
set_response!(response)
|
190
188
|
process(name)
|
@@ -196,12 +194,12 @@ module ActionController
|
|
196
194
|
@_response = response
|
197
195
|
end
|
198
196
|
|
199
|
-
def set_request!(request)
|
197
|
+
def set_request!(request) # :nodoc:
|
200
198
|
@_request = request
|
201
199
|
@_request.controller_instance = self
|
202
200
|
end
|
203
201
|
|
204
|
-
def to_a
|
202
|
+
def to_a # :nodoc:
|
205
203
|
response.to_a
|
206
204
|
end
|
207
205
|
|
@@ -219,10 +217,9 @@ module ActionController
|
|
219
217
|
class << self
|
220
218
|
# Pushes the given Rack middleware and its arguments to the bottom of the
|
221
219
|
# middleware stack.
|
222
|
-
def use(
|
223
|
-
middleware_stack.use(
|
220
|
+
def use(...)
|
221
|
+
middleware_stack.use(...)
|
224
222
|
end
|
225
|
-
ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
|
226
223
|
end
|
227
224
|
|
228
225
|
# Alias for +middleware_stack+.
|
@@ -8,8 +8,11 @@ require "action_controller/railties/helpers"
|
|
8
8
|
require "action_view/railtie"
|
9
9
|
|
10
10
|
module ActionController
|
11
|
-
class Railtie < Rails::Railtie
|
11
|
+
class Railtie < Rails::Railtie # :nodoc:
|
12
12
|
config.action_controller = ActiveSupport::OrderedOptions.new
|
13
|
+
config.action_controller.raise_on_open_redirects = false
|
14
|
+
config.action_controller.log_query_tags_around_actions = true
|
15
|
+
config.action_controller.wrap_parameters_by_default = false
|
13
16
|
|
14
17
|
config.eager_load_namespaces << ActionController
|
15
18
|
|
@@ -25,14 +28,19 @@ module ActionController
|
|
25
28
|
options = app.config.action_controller
|
26
29
|
|
27
30
|
ActiveSupport.on_load(:action_controller, run_once: true) do
|
28
|
-
ActionController::Parameters.permit_all_parameters = options.
|
31
|
+
ActionController::Parameters.permit_all_parameters = options.permit_all_parameters || false
|
29
32
|
if app.config.action_controller[:always_permitted_parameters]
|
30
33
|
ActionController::Parameters.always_permitted_parameters =
|
31
|
-
app.config.action_controller.
|
34
|
+
app.config.action_controller.always_permitted_parameters
|
32
35
|
end
|
33
|
-
|
34
|
-
|
36
|
+
|
37
|
+
action_on_unpermitted_parameters = options.action_on_unpermitted_parameters
|
38
|
+
|
39
|
+
if action_on_unpermitted_parameters.nil?
|
40
|
+
action_on_unpermitted_parameters = (Rails.env.test? || Rails.env.development?) ? :log : false
|
35
41
|
end
|
42
|
+
|
43
|
+
ActionController::Parameters.action_on_unpermitted_parameters = action_on_unpermitted_parameters
|
36
44
|
end
|
37
45
|
end
|
38
46
|
|
@@ -55,7 +63,18 @@ module ActionController
|
|
55
63
|
extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
|
56
64
|
extend ::ActionController::Railties::Helpers
|
57
65
|
|
58
|
-
options.
|
66
|
+
wrap_parameters format: [:json] if options.wrap_parameters_by_default && respond_to?(:wrap_parameters)
|
67
|
+
|
68
|
+
# Configs used in other initializers
|
69
|
+
filtered_options = options.except(
|
70
|
+
:log_query_tags_around_actions,
|
71
|
+
:permit_all_parameters,
|
72
|
+
:action_on_unpermitted_parameters,
|
73
|
+
:always_permitted_parameters,
|
74
|
+
:wrap_parameters_by_default
|
75
|
+
)
|
76
|
+
|
77
|
+
filtered_options.each do |k, v|
|
59
78
|
k = "#{k}="
|
60
79
|
if respond_to?(k)
|
61
80
|
send(k, v)
|
@@ -85,5 +104,29 @@ module ActionController
|
|
85
104
|
ActionController::Metal.descendants.each(&:action_methods) if config.eager_load
|
86
105
|
end
|
87
106
|
end
|
107
|
+
|
108
|
+
initializer "action_controller.query_log_tags" do |app|
|
109
|
+
query_logs_tags_enabled = app.config.respond_to?(:active_record) &&
|
110
|
+
app.config.active_record.query_log_tags_enabled &&
|
111
|
+
app.config.action_controller.log_query_tags_around_actions
|
112
|
+
|
113
|
+
if query_logs_tags_enabled
|
114
|
+
app.config.active_record.query_log_tags += [:controller, :action]
|
115
|
+
|
116
|
+
ActiveSupport.on_load(:active_record) do
|
117
|
+
ActiveRecord::QueryLogs.taggings.merge!(
|
118
|
+
controller: ->(context) { context[:controller]&.controller_name },
|
119
|
+
action: ->(context) { context[:controller]&.action_name },
|
120
|
+
namespaced_controller: ->(context) { context[:controller].class.name if context[:controller] }
|
121
|
+
)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
initializer "action_controller.test_case" do |app|
|
127
|
+
ActiveSupport.on_load(:action_controller_test_case) do
|
128
|
+
ActionController::TestCase.executor_around_each_request = app.config.active_support.executor_around_test_case
|
129
|
+
end
|
130
|
+
end
|
88
131
|
end
|
89
132
|
end
|
@@ -71,7 +71,7 @@ module ActionController
|
|
71
71
|
# Render templates with any options from ActionController::Base#render_to_string.
|
72
72
|
#
|
73
73
|
# The primary options are:
|
74
|
-
# * <tt>:partial</tt> - See
|
74
|
+
# * <tt>:partial</tt> - See ActionView::PartialRenderer for details.
|
75
75
|
# * <tt>:file</tt> - Renders an explicit template file. Add <tt>:locals</tt> to pass in, if so desired.
|
76
76
|
# It shouldn’t be used directly with unsanitized user input due to lack of validation.
|
77
77
|
# * <tt>:inline</tt> - Renders an ERB template string.
|
@@ -31,7 +31,7 @@ module ActionController
|
|
31
31
|
|
32
32
|
# ActionController::TestCase will be deprecated and moved to a gem in the future.
|
33
33
|
# Please use ActionDispatch::IntegrationTest going forward.
|
34
|
-
class TestRequest < ActionDispatch::TestRequest
|
34
|
+
class TestRequest < ActionDispatch::TestRequest # :nodoc:
|
35
35
|
DEFAULT_ENV = ActionDispatch::TestRequest::DEFAULT_ENV.dup
|
36
36
|
DEFAULT_ENV.delete "PATH_INFO"
|
37
37
|
|
@@ -179,7 +179,7 @@ module ActionController
|
|
179
179
|
|
180
180
|
# Methods #destroy and #load! are overridden to avoid calling methods on the
|
181
181
|
# @store object, which does not exist for the TestSession class.
|
182
|
-
class TestSession < Rack::Session::Abstract::PersistedSecure::SecureSessionHash
|
182
|
+
class TestSession < Rack::Session::Abstract::PersistedSecure::SecureSessionHash # :nodoc:
|
183
183
|
DEFAULT_OPTIONS = Rack::Session::Abstract::Persisted::DEFAULT_OPTIONS
|
184
184
|
|
185
185
|
def initialize(session = {})
|
@@ -214,6 +214,10 @@ module ActionController
|
|
214
214
|
@data.fetch(key.to_s, *args, &block)
|
215
215
|
end
|
216
216
|
|
217
|
+
def enabled?
|
218
|
+
true
|
219
|
+
end
|
220
|
+
|
217
221
|
private
|
218
222
|
def load!
|
219
223
|
@id
|
@@ -237,7 +241,7 @@ module ActionController
|
|
237
241
|
# == Basic example
|
238
242
|
#
|
239
243
|
# Functional tests are written as follows:
|
240
|
-
# 1. First, one uses the +get+, +post+, +patch+, +put+, +delete
|
244
|
+
# 1. First, one uses the +get+, +post+, +patch+, +put+, +delete+, or +head+ method to simulate
|
241
245
|
# an HTTP request.
|
242
246
|
# 2. Then, one asserts whether the current state is as expected. "State" can be anything:
|
243
247
|
# the controller's HTTP response, the database contents, etc.
|
@@ -329,6 +333,8 @@ module ActionController
|
|
329
333
|
#
|
330
334
|
# assert_redirected_to page_url(title: 'foo')
|
331
335
|
class TestCase < ActiveSupport::TestCase
|
336
|
+
singleton_class.attr_accessor :executor_around_each_request
|
337
|
+
|
332
338
|
module Behavior
|
333
339
|
extend ActiveSupport::Concern
|
334
340
|
include ActionDispatch::TestProcess
|
@@ -385,7 +391,7 @@ module ActionController
|
|
385
391
|
#
|
386
392
|
# You can also simulate POST, PATCH, PUT, DELETE, and HEAD requests with
|
387
393
|
# +post+, +patch+, +put+, +delete+, and +head+.
|
388
|
-
# Example sending parameters, session and setting a flash message:
|
394
|
+
# Example sending parameters, session, and setting a flash message:
|
389
395
|
#
|
390
396
|
# get :show,
|
391
397
|
# params: { id: 7 },
|
@@ -455,13 +461,19 @@ module ActionController
|
|
455
461
|
# session: { user_id: 1 },
|
456
462
|
# flash: { notice: 'This is flash message' }
|
457
463
|
#
|
458
|
-
# To simulate +GET+, +POST+, +PATCH+, +PUT+, +DELETE
|
464
|
+
# To simulate +GET+, +POST+, +PATCH+, +PUT+, +DELETE+, and +HEAD+ requests
|
459
465
|
# prefer using #get, #post, #patch, #put, #delete and #head methods
|
460
466
|
# respectively which will make tests more expressive.
|
461
467
|
#
|
468
|
+
# It's not recommended to make more than one request in the same test. Instance
|
469
|
+
# variables that are set in one request will not persist to the next request,
|
470
|
+
# but it's not guaranteed that all Rails internal state will be reset. Prefer
|
471
|
+
# ActionDispatch::IntegrationTest for making multiple requests in the same test.
|
472
|
+
#
|
462
473
|
# Note that the request method is not verified.
|
463
474
|
def process(action, method: "GET", params: nil, session: nil, body: nil, flash: {}, format: nil, xhr: false, as: nil)
|
464
475
|
check_required_ivars
|
476
|
+
@controller.clear_instance_variables_between_requests
|
465
477
|
|
466
478
|
action = +action.to_s
|
467
479
|
http_method = method.to_s.upcase
|
@@ -574,10 +586,19 @@ module ActionController
|
|
574
586
|
end
|
575
587
|
end
|
576
588
|
|
589
|
+
def wrap_execution(&block)
|
590
|
+
if ActionController::TestCase.executor_around_each_request && defined?(Rails.application) && Rails.application
|
591
|
+
Rails.application.executor.wrap(&block)
|
592
|
+
else
|
593
|
+
yield
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
577
597
|
def process_controller_response(action, cookies, xhr)
|
578
598
|
begin
|
579
599
|
@controller.recycle!
|
580
|
-
|
600
|
+
|
601
|
+
wrap_execution { @controller.dispatch(action, @request, @response) }
|
581
602
|
ensure
|
582
603
|
@request = @controller.request
|
583
604
|
@response = @controller.response
|
@@ -623,7 +644,7 @@ module ActionController
|
|
623
644
|
end
|
624
645
|
|
625
646
|
def check_required_ivars
|
626
|
-
#
|
647
|
+
# Check for required instance variables so we can give an
|
627
648
|
# understandable error message.
|
628
649
|
[:@routes, :@controller, :@request, :@response].each do |iv_name|
|
629
650
|
if !instance_variable_defined?(iv_name) || instance_variable_get(iv_name).nil?
|