actionpack 5.2.1 → 7.0.2.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 +264 -220
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -6
- data/lib/abstract_controller/asset_paths.rb +1 -1
- data/lib/abstract_controller/base.rb +24 -4
- data/lib/abstract_controller/caching/fragments.rb +8 -24
- data/lib/abstract_controller/caching.rb +2 -2
- data/lib/abstract_controller/callbacks.rb +34 -8
- data/lib/abstract_controller/collector.rb +5 -4
- data/lib/abstract_controller/error.rb +1 -1
- data/lib/abstract_controller/helpers.rb +107 -90
- data/lib/abstract_controller/logger.rb +1 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +19 -1
- data/lib/abstract_controller/rendering.rb +9 -9
- data/lib/abstract_controller/translation.rb +12 -5
- data/lib/abstract_controller/url_for.rb +4 -6
- data/lib/abstract_controller.rb +2 -0
- data/lib/action_controller/api.rb +5 -4
- data/lib/action_controller/base.rb +6 -9
- data/lib/action_controller/caching.rb +1 -3
- data/lib/action_controller/log_subscriber.rb +13 -9
- data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
- data/lib/action_controller/metal/conditional_get.rb +57 -6
- data/lib/action_controller/metal/content_security_policy.rb +2 -3
- data/lib/action_controller/metal/cookies.rb +4 -2
- data/lib/action_controller/metal/data_streaming.rb +9 -18
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +4 -6
- data/lib/action_controller/metal/exceptions.rb +55 -12
- data/lib/action_controller/metal/flash.rb +10 -6
- data/lib/action_controller/metal/head.rb +7 -4
- data/lib/action_controller/metal/helpers.rb +15 -6
- data/lib/action_controller/metal/http_authentication.rb +41 -39
- data/lib/action_controller/metal/implicit_render.rb +5 -15
- data/lib/action_controller/metal/instrumentation.rb +59 -55
- data/lib/action_controller/metal/live.rb +80 -33
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +22 -7
- data/lib/action_controller/metal/parameter_encoding.rb +35 -4
- data/lib/action_controller/metal/params_wrapper.rb +50 -31
- data/lib/action_controller/metal/permissions_policy.rb +46 -0
- data/lib/action_controller/metal/redirecting.rb +93 -23
- data/lib/action_controller/metal/renderers.rb +4 -4
- data/lib/action_controller/metal/rendering.rb +14 -9
- data/lib/action_controller/metal/request_forgery_protection.rb +160 -58
- data/lib/action_controller/metal/rescue.rb +2 -2
- data/lib/action_controller/metal/streaming.rb +1 -4
- data/lib/action_controller/metal/strong_parameters.rb +236 -88
- data/lib/action_controller/metal/testing.rb +9 -2
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/metal.rb +16 -17
- data/lib/action_controller/railtie.rb +49 -6
- data/lib/action_controller/railties/helpers.rb +1 -1
- data/lib/action_controller/renderer.rb +37 -13
- data/lib/action_controller/template_assertions.rb +1 -1
- data/lib/action_controller/test_case.rb +98 -68
- data/lib/action_controller.rb +4 -5
- data/lib/action_dispatch/http/cache.rb +45 -32
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +69 -56
- data/lib/action_dispatch/http/filter_parameters.rb +14 -8
- data/lib/action_dispatch/http/filter_redirect.rb +2 -3
- data/lib/action_dispatch/http/headers.rb +4 -4
- data/lib/action_dispatch/http/mime_negotiation.rb +44 -16
- data/lib/action_dispatch/http/mime_type.rb +47 -30
- data/lib/action_dispatch/http/parameters.rb +18 -27
- data/lib/action_dispatch/http/permissions_policy.rb +173 -0
- data/lib/action_dispatch/http/request.rb +49 -35
- data/lib/action_dispatch/http/response.rb +34 -26
- data/lib/action_dispatch/http/upload.rb +9 -1
- data/lib/action_dispatch/http/url.rb +86 -94
- data/lib/action_dispatch/journey/formatter.rb +55 -31
- data/lib/action_dispatch/journey/gtg/builder.rb +30 -46
- data/lib/action_dispatch/journey/gtg/simulator.rb +15 -8
- data/lib/action_dispatch/journey/gtg/transition_table.rb +78 -21
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
- data/lib/action_dispatch/journey/nodes/node.rb +83 -16
- data/lib/action_dispatch/journey/parser.rb +13 -13
- data/lib/action_dispatch/journey/parser.y +1 -1
- data/lib/action_dispatch/journey/path/pattern.rb +42 -34
- data/lib/action_dispatch/journey/route.rb +14 -31
- data/lib/action_dispatch/journey/router/utils.rb +16 -14
- data/lib/action_dispatch/journey/router.rb +27 -35
- data/lib/action_dispatch/journey/routes.rb +3 -5
- data/lib/action_dispatch/journey/scanner.rb +10 -4
- data/lib/action_dispatch/journey/visitors.rb +1 -4
- 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/journey.rb +0 -2
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +45 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -4
- data/lib/action_dispatch/middleware/cookies.rb +136 -113
- data/lib/action_dispatch/middleware/debug_exceptions.rb +47 -68
- data/lib/action_dispatch/middleware/debug_locks.rb +8 -8
- data/lib/action_dispatch/middleware/debug_view.rb +66 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +79 -30
- data/lib/action_dispatch/middleware/executor.rb +4 -1
- data/lib/action_dispatch/middleware/flash.rb +10 -12
- data/lib/action_dispatch/middleware/host_authorization.rb +159 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +30 -20
- data/lib/action_dispatch/middleware/request_id.rb +5 -6
- data/lib/action_dispatch/middleware/server_timing.rb +33 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +16 -3
- data/lib/action_dispatch/middleware/session/cache_store.rb +11 -6
- data/lib/action_dispatch/middleware/session/cookie_store.rb +24 -19
- data/lib/action_dispatch/middleware/show_exceptions.rb +20 -11
- data/lib/action_dispatch/middleware/ssl.rb +20 -15
- data/lib/action_dispatch/middleware/stack.rb +79 -7
- data/lib/action_dispatch/middleware/static.rb +150 -94
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +6 -11
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +46 -36
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +25 -6
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +9 -6
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -1
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +121 -15
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +5 -5
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +5 -5
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +16 -2
- data/lib/action_dispatch/railtie.rb +16 -4
- data/lib/action_dispatch/request/session.rb +59 -22
- data/lib/action_dispatch/request/utils.rb +28 -2
- data/lib/action_dispatch/routing/inspector.rb +102 -54
- data/lib/action_dispatch/routing/mapper.rb +184 -156
- data/lib/action_dispatch/routing/polymorphic_routes.rb +21 -19
- data/lib/action_dispatch/routing/redirection.rb +4 -6
- data/lib/action_dispatch/routing/route_set.rb +83 -73
- data/lib/action_dispatch/routing/routes_proxy.rb +1 -1
- data/lib/action_dispatch/routing/url_for.rb +2 -3
- data/lib/action_dispatch/routing.rb +23 -22
- data/lib/action_dispatch/system_test_case.rb +65 -16
- data/lib/action_dispatch/system_testing/browser.rb +43 -16
- data/lib/action_dispatch/system_testing/driver.rb +42 -10
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +58 -12
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +3 -10
- data/lib/action_dispatch/testing/assertion_response.rb +0 -1
- data/lib/action_dispatch/testing/assertions/response.rb +4 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
- data/lib/action_dispatch/testing/assertions.rb +3 -6
- data/lib/action_dispatch/testing/integration.rb +61 -30
- data/lib/action_dispatch/testing/request_encoder.rb +2 -2
- data/lib/action_dispatch/testing/test_process.rb +8 -6
- data/lib/action_dispatch/testing/test_request.rb +3 -3
- data/lib/action_dispatch/testing/test_response.rb +4 -32
- data/lib/action_dispatch.rb +15 -7
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack.rb +1 -1
- metadata +44 -25
- data/lib/action_controller/metal/force_ssl.rb +0 -99
- data/lib/action_dispatch/http/parameter_filter.rb +0 -86
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module ActionController
|
3
|
+
module ActionController # :nodoc:
|
4
4
|
# This module is responsible for providing +rescue_from+ helpers
|
5
5
|
# to controllers and configuring when detailed exceptions must be
|
6
6
|
# shown.
|
@@ -18,7 +18,7 @@ module ActionController #:nodoc:
|
|
18
18
|
end
|
19
19
|
|
20
20
|
private
|
21
|
-
def process_action(*
|
21
|
+
def process_action(*)
|
22
22
|
super
|
23
23
|
rescue Exception => exception
|
24
24
|
request.env["action_dispatch.show_detailed_exceptions"] ||= show_detailed_exceptions?
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require "rack/chunked"
|
4
4
|
|
5
|
-
module ActionController
|
5
|
+
module ActionController # :nodoc:
|
6
6
|
# Allows views to be streamed back to the client as they are rendered.
|
7
7
|
#
|
8
8
|
# By default, Rails renders views by first rendering the template
|
@@ -193,10 +193,7 @@ module ActionController #:nodoc:
|
|
193
193
|
# To be described.
|
194
194
|
#
|
195
195
|
module Streaming
|
196
|
-
extend ActiveSupport::Concern
|
197
|
-
|
198
196
|
private
|
199
|
-
|
200
197
|
# Set proper cache control and transfer encoding when streaming
|
201
198
|
def _process_options(options)
|
202
199
|
super
|
@@ -1,11 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/hash/indifferent_access"
|
4
|
-
require "active_support/core_ext/hash/transform_values"
|
5
4
|
require "active_support/core_ext/array/wrap"
|
6
5
|
require "active_support/core_ext/string/filters"
|
7
6
|
require "active_support/core_ext/object/to_query"
|
8
|
-
require "active_support/rescuable"
|
9
7
|
require "action_dispatch/http/upload"
|
10
8
|
require "rack/test"
|
11
9
|
require "stringio"
|
@@ -21,12 +19,21 @@ module ActionController
|
|
21
19
|
# params.require(:a)
|
22
20
|
# # => ActionController::ParameterMissing: param is missing or the value is empty: a
|
23
21
|
class ParameterMissing < KeyError
|
24
|
-
attr_reader :param # :nodoc:
|
22
|
+
attr_reader :param, :keys # :nodoc:
|
25
23
|
|
26
|
-
def initialize(param) # :nodoc:
|
24
|
+
def initialize(param, keys = nil) # :nodoc:
|
27
25
|
@param = param
|
26
|
+
@keys = keys
|
28
27
|
super("param is missing or the value is empty: #{param}")
|
29
28
|
end
|
29
|
+
|
30
|
+
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
31
|
+
include DidYouMean::Correctable # :nodoc:
|
32
|
+
|
33
|
+
def corrections # :nodoc:
|
34
|
+
@corrections ||= DidYouMean::SpellChecker.new(dictionary: keys).correct(param.to_s)
|
35
|
+
end
|
36
|
+
end
|
30
37
|
end
|
31
38
|
|
32
39
|
# Raised when a supplied parameter is not expected and
|
@@ -59,7 +66,7 @@ module ActionController
|
|
59
66
|
|
60
67
|
# == Action Controller \Parameters
|
61
68
|
#
|
62
|
-
# Allows you to choose which attributes should be
|
69
|
+
# Allows you to choose which attributes should be permitted for mass updating
|
63
70
|
# and thus prevent accidentally exposing that which shouldn't be exposed.
|
64
71
|
# Provides two methods for this purpose: #require and #permit. The former is
|
65
72
|
# used to mark parameters as required. The latter is used to set the parameter
|
@@ -74,7 +81,7 @@ module ActionController
|
|
74
81
|
# })
|
75
82
|
#
|
76
83
|
# permitted = params.require(:person).permit(:name, :age)
|
77
|
-
# permitted # =>
|
84
|
+
# permitted # => #<ActionController::Parameters {"name"=>"Francesco", "age"=>22} permitted: true>
|
78
85
|
# permitted.permitted? # => true
|
79
86
|
#
|
80
87
|
# Person.first.update!(permitted)
|
@@ -84,11 +91,13 @@ module ActionController
|
|
84
91
|
#
|
85
92
|
# * +permit_all_parameters+ - If it's +true+, all the parameters will be
|
86
93
|
# permitted by default. The default is +false+.
|
87
|
-
# * +action_on_unpermitted_parameters+ -
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
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.
|
92
101
|
#
|
93
102
|
# Examples:
|
94
103
|
#
|
@@ -102,7 +111,7 @@ module ActionController
|
|
102
111
|
#
|
103
112
|
# params = ActionController::Parameters.new(a: "123", b: "456")
|
104
113
|
# params.permit(:c)
|
105
|
-
# # =>
|
114
|
+
# # => #<ActionController::Parameters {} permitted: true>
|
106
115
|
#
|
107
116
|
# ActionController::Parameters.action_on_unpermitted_parameters = :raise
|
108
117
|
#
|
@@ -133,6 +142,15 @@ module ActionController
|
|
133
142
|
#
|
134
143
|
# Returns a hash that can be used as the JSON representation for the parameters.
|
135
144
|
|
145
|
+
##
|
146
|
+
# :method: each_key
|
147
|
+
#
|
148
|
+
# :call-seq:
|
149
|
+
# each_key()
|
150
|
+
#
|
151
|
+
# Calls block once for each key in the parameters, passing the key.
|
152
|
+
# If no block is given, an enumerator is returned instead.
|
153
|
+
|
136
154
|
##
|
137
155
|
# :method: empty?
|
138
156
|
#
|
@@ -173,6 +191,14 @@ module ActionController
|
|
173
191
|
#
|
174
192
|
# Returns true if the given key is present in the parameters.
|
175
193
|
|
194
|
+
##
|
195
|
+
# :method: member?
|
196
|
+
#
|
197
|
+
# :call-seq:
|
198
|
+
# member?(key)
|
199
|
+
#
|
200
|
+
# Returns true if the given key is present in the parameters.
|
201
|
+
|
176
202
|
##
|
177
203
|
# :method: keys
|
178
204
|
#
|
@@ -204,8 +230,8 @@ module ActionController
|
|
204
230
|
# values()
|
205
231
|
#
|
206
232
|
# Returns a new array of the values of the parameters.
|
207
|
-
delegate :keys, :key?, :has_key?, :values, :has_value?, :value?, :empty?, :include?,
|
208
|
-
:as_json, :to_s, to: :@parameters
|
233
|
+
delegate :keys, :key?, :has_key?, :member?, :values, :has_value?, :value?, :empty?, :include?,
|
234
|
+
:as_json, :to_s, :each_key, to: :@parameters
|
209
235
|
|
210
236
|
# By default, never raise an UnpermittedParameters exception if these
|
211
237
|
# params are present. The default includes both 'controller' and 'action'
|
@@ -213,9 +239,15 @@ module ActionController
|
|
213
239
|
# to change these is to specify `always_permitted_parameters` in your
|
214
240
|
# config. For instance:
|
215
241
|
#
|
216
|
-
# config.always_permitted_parameters = %w( controller action format )
|
242
|
+
# config.action_controller.always_permitted_parameters = %w( controller action format )
|
217
243
|
cattr_accessor :always_permitted_parameters, default: %w( controller action )
|
218
244
|
|
245
|
+
class << self
|
246
|
+
def nested_attribute?(key, value) # :nodoc:
|
247
|
+
/\A-?\d+\z/.match?(key) && (value.is_a?(Hash) || value.is_a?(Parameters))
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
219
251
|
# Returns a new instance of <tt>ActionController::Parameters</tt>.
|
220
252
|
# Also, sets the +permitted+ attribute to the default value of
|
221
253
|
# <tt>ActionController::Parameters.permit_all_parameters</tt>.
|
@@ -232,8 +264,9 @@ module ActionController
|
|
232
264
|
# params = ActionController::Parameters.new(name: "Francesco")
|
233
265
|
# params.permitted? # => true
|
234
266
|
# Person.new(params) # => #<Person id: nil, name: "Francesco">
|
235
|
-
def initialize(parameters = {})
|
267
|
+
def initialize(parameters = {}, logging_context = {})
|
236
268
|
@parameters = parameters.with_indifferent_access
|
269
|
+
@logging_context = logging_context
|
237
270
|
@permitted = self.class.permit_all_parameters
|
238
271
|
end
|
239
272
|
|
@@ -246,6 +279,11 @@ module ActionController
|
|
246
279
|
@parameters == other
|
247
280
|
end
|
248
281
|
end
|
282
|
+
alias eql? ==
|
283
|
+
|
284
|
+
def hash
|
285
|
+
[@parameters.hash, @permitted].hash
|
286
|
+
end
|
249
287
|
|
250
288
|
# Returns a safe <tt>ActiveSupport::HashWithIndifferentAccess</tt>
|
251
289
|
# representation of the parameters with all unpermitted keys removed.
|
@@ -334,12 +372,26 @@ module ActionController
|
|
334
372
|
# Convert all hashes in values into parameters, then yield each pair in
|
335
373
|
# the same way as <tt>Hash#each_pair</tt>.
|
336
374
|
def each_pair(&block)
|
375
|
+
return to_enum(__callee__) unless block_given?
|
337
376
|
@parameters.each_pair do |key, value|
|
338
377
|
yield [key, convert_hashes_to_parameters(key, value)]
|
339
378
|
end
|
379
|
+
|
380
|
+
self
|
340
381
|
end
|
341
382
|
alias_method :each, :each_pair
|
342
383
|
|
384
|
+
# Convert all hashes in values into parameters, then yield each value in
|
385
|
+
# the same way as <tt>Hash#each_value</tt>.
|
386
|
+
def each_value(&block)
|
387
|
+
return to_enum(:each_value) unless block_given?
|
388
|
+
@parameters.each_pair do |key, value|
|
389
|
+
yield convert_hashes_to_parameters(key, value)
|
390
|
+
end
|
391
|
+
|
392
|
+
self
|
393
|
+
end
|
394
|
+
|
343
395
|
# Attribute that keeps track of converted arrays, if any, to avoid double
|
344
396
|
# looping in the common use case permit + mass-assignment. Defined in a
|
345
397
|
# method to instantiate it only if needed.
|
@@ -390,7 +442,7 @@ module ActionController
|
|
390
442
|
# either present or the singleton +false+, returns said value:
|
391
443
|
#
|
392
444
|
# ActionController::Parameters.new(person: { name: "Francesco" }).require(:person)
|
393
|
-
# # =>
|
445
|
+
# # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
394
446
|
#
|
395
447
|
# Otherwise raises <tt>ActionController::ParameterMissing</tt>:
|
396
448
|
#
|
@@ -440,7 +492,7 @@ module ActionController
|
|
440
492
|
if value.present? || value == false
|
441
493
|
value
|
442
494
|
else
|
443
|
-
raise ParameterMissing.new(key)
|
495
|
+
raise ParameterMissing.new(key, @parameters.keys)
|
444
496
|
end
|
445
497
|
end
|
446
498
|
|
@@ -506,7 +558,7 @@ module ActionController
|
|
506
558
|
#
|
507
559
|
# Note that if you use +permit+ in a key that points to a hash,
|
508
560
|
# it won't allow all the hash. You also need to specify which
|
509
|
-
# attributes inside the hash should be
|
561
|
+
# attributes inside the hash should be permitted.
|
510
562
|
#
|
511
563
|
# params = ActionController::Parameters.new({
|
512
564
|
# person: {
|
@@ -518,13 +570,48 @@ module ActionController
|
|
518
570
|
# })
|
519
571
|
#
|
520
572
|
# params.require(:person).permit(:contact)
|
521
|
-
# # =>
|
573
|
+
# # => #<ActionController::Parameters {} permitted: true>
|
522
574
|
#
|
523
575
|
# params.require(:person).permit(contact: :phone)
|
524
|
-
# # =>
|
576
|
+
# # => #<ActionController::Parameters {"contact"=>#<ActionController::Parameters {"phone"=>"555-1234"} permitted: true>} permitted: true>
|
525
577
|
#
|
526
578
|
# params.require(:person).permit(contact: [ :email, :phone ])
|
527
|
-
# # =>
|
579
|
+
# # => #<ActionController::Parameters {"contact"=>#<ActionController::Parameters {"email"=>"none@test.com", "phone"=>"555-1234"} permitted: true>} permitted: true>
|
580
|
+
#
|
581
|
+
# If your parameters specify multiple parameters indexed by a number,
|
582
|
+
# you can permit each set of parameters under the numeric key to be the same using the same syntax as permitting a single item.
|
583
|
+
#
|
584
|
+
# params = ActionController::Parameters.new({
|
585
|
+
# person: {
|
586
|
+
# '0': {
|
587
|
+
# email: "none@test.com",
|
588
|
+
# phone: "555-1234"
|
589
|
+
# },
|
590
|
+
# '1': {
|
591
|
+
# email: "nothing@test.com",
|
592
|
+
# phone: "555-6789"
|
593
|
+
# },
|
594
|
+
# }
|
595
|
+
# })
|
596
|
+
# params.permit(person: [:email]).to_h
|
597
|
+
# # => {"person"=>{"0"=>{"email"=>"none@test.com"}, "1"=>{"email"=>"nothing@test.com"}}}
|
598
|
+
#
|
599
|
+
# If you want to specify what keys you want from each numeric key, you can instead specify each one individually
|
600
|
+
#
|
601
|
+
# params = ActionController::Parameters.new({
|
602
|
+
# person: {
|
603
|
+
# '0': {
|
604
|
+
# email: "none@test.com",
|
605
|
+
# phone: "555-1234"
|
606
|
+
# },
|
607
|
+
# '1': {
|
608
|
+
# email: "nothing@test.com",
|
609
|
+
# phone: "555-6789"
|
610
|
+
# },
|
611
|
+
# }
|
612
|
+
# })
|
613
|
+
# params.permit(person: { '0': [:email], '1': [:phone]}).to_h
|
614
|
+
# # => {"person"=>{"0"=>{"email"=>"none@test.com"}, "1"=>{"phone"=>"555-6789"}}}
|
528
615
|
def permit(*filters)
|
529
616
|
params = self.class.new
|
530
617
|
|
@@ -546,7 +633,7 @@ module ActionController
|
|
546
633
|
# returns +nil+.
|
547
634
|
#
|
548
635
|
# params = ActionController::Parameters.new(person: { name: "Francesco" })
|
549
|
-
# params[:person] # =>
|
636
|
+
# params[:person] # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
550
637
|
# params[:none] # => nil
|
551
638
|
def [](key)
|
552
639
|
convert_hashes_to_parameters(key, @parameters[key])
|
@@ -566,9 +653,9 @@ module ActionController
|
|
566
653
|
# is given, then that will be run and its result returned.
|
567
654
|
#
|
568
655
|
# params = ActionController::Parameters.new(person: { name: "Francesco" })
|
569
|
-
# params.fetch(:person) # =>
|
656
|
+
# params.fetch(:person) # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
570
657
|
# params.fetch(:none) # => ActionController::ParameterMissing: param is missing or the value is empty: none
|
571
|
-
# params.fetch(:none, {}) # =>
|
658
|
+
# params.fetch(:none, {}) # => #<ActionController::Parameters {} permitted: false>
|
572
659
|
# params.fetch(:none, "Francesco") # => "Francesco"
|
573
660
|
# params.fetch(:none) { "Francesco" } # => "Francesco"
|
574
661
|
def fetch(key, *args)
|
@@ -577,26 +664,24 @@ module ActionController
|
|
577
664
|
if block_given?
|
578
665
|
yield
|
579
666
|
else
|
580
|
-
args.fetch(0) { raise ActionController::ParameterMissing.new(key) }
|
667
|
+
args.fetch(0) { raise ActionController::ParameterMissing.new(key, @parameters.keys) }
|
581
668
|
end
|
582
669
|
}
|
583
670
|
)
|
584
671
|
end
|
585
672
|
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
@parameters.dig(*keys)
|
599
|
-
end
|
673
|
+
# Extracts the nested parameter from the given +keys+ by calling +dig+
|
674
|
+
# at each step. Returns +nil+ if any intermediate step is +nil+.
|
675
|
+
#
|
676
|
+
# params = ActionController::Parameters.new(foo: { bar: { baz: 1 } })
|
677
|
+
# params.dig(:foo, :bar, :baz) # => 1
|
678
|
+
# params.dig(:foo, :zot, :xyz) # => nil
|
679
|
+
#
|
680
|
+
# params2 = ActionController::Parameters.new(foo: [10, 11, 12])
|
681
|
+
# params2.dig(:foo, 1) # => 11
|
682
|
+
def dig(*keys)
|
683
|
+
convert_hashes_to_parameters(keys.first, @parameters[keys.first])
|
684
|
+
@parameters.dig(*keys)
|
600
685
|
end
|
601
686
|
|
602
687
|
# Returns a new <tt>ActionController::Parameters</tt> instance that
|
@@ -604,8 +689,8 @@ module ActionController
|
|
604
689
|
# don't exist, returns an empty hash.
|
605
690
|
#
|
606
691
|
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
607
|
-
# params.slice(:a, :b) # =>
|
608
|
-
# params.slice(:d) # =>
|
692
|
+
# params.slice(:a, :b) # => #<ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
|
693
|
+
# params.slice(:d) # => #<ActionController::Parameters {} permitted: false>
|
609
694
|
def slice(*keys)
|
610
695
|
new_instance_with_inherited_permitted_status(@parameters.slice(*keys))
|
611
696
|
end
|
@@ -621,8 +706,8 @@ module ActionController
|
|
621
706
|
# filters out the given +keys+.
|
622
707
|
#
|
623
708
|
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
624
|
-
# params.except(:a, :b) # =>
|
625
|
-
# params.except(:d) # =>
|
709
|
+
# params.except(:a, :b) # => #<ActionController::Parameters {"c"=>3} permitted: false>
|
710
|
+
# params.except(:d) # => #<ActionController::Parameters {"a"=>1, "b"=>2, "c"=>3} permitted: false>
|
626
711
|
def except(*keys)
|
627
712
|
new_instance_with_inherited_permitted_status(@parameters.except(*keys))
|
628
713
|
end
|
@@ -630,8 +715,8 @@ module ActionController
|
|
630
715
|
# Removes and returns the key/value pairs matching the given keys.
|
631
716
|
#
|
632
717
|
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
633
|
-
# params.extract!(:a, :b) # =>
|
634
|
-
# params # =>
|
718
|
+
# params.extract!(:a, :b) # => #<ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
|
719
|
+
# params # => #<ActionController::Parameters {"c"=>3} permitted: false>
|
635
720
|
def extract!(*keys)
|
636
721
|
new_instance_with_inherited_permitted_status(@parameters.extract!(*keys))
|
637
722
|
end
|
@@ -641,7 +726,7 @@ module ActionController
|
|
641
726
|
#
|
642
727
|
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
643
728
|
# params.transform_values { |x| x * 2 }
|
644
|
-
# # =>
|
729
|
+
# # => #<ActionController::Parameters {"a"=>2, "b"=>4, "c"=>6} permitted: false>
|
645
730
|
def transform_values
|
646
731
|
return to_enum(:transform_values) unless block_given?
|
647
732
|
new_instance_with_inherited_permitted_status(
|
@@ -660,22 +745,37 @@ module ActionController
|
|
660
745
|
# Returns a new <tt>ActionController::Parameters</tt> instance with the
|
661
746
|
# results of running +block+ once for every key. The values are unchanged.
|
662
747
|
def transform_keys(&block)
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
else
|
668
|
-
@parameters.transform_keys
|
669
|
-
end
|
748
|
+
return to_enum(:transform_keys) unless block_given?
|
749
|
+
new_instance_with_inherited_permitted_status(
|
750
|
+
@parameters.transform_keys(&block)
|
751
|
+
)
|
670
752
|
end
|
671
753
|
|
672
754
|
# Performs keys transformation and returns the altered
|
673
755
|
# <tt>ActionController::Parameters</tt> instance.
|
674
756
|
def transform_keys!(&block)
|
757
|
+
return to_enum(:transform_keys!) unless block_given?
|
675
758
|
@parameters.transform_keys!(&block)
|
676
759
|
self
|
677
760
|
end
|
678
761
|
|
762
|
+
# Returns a new <tt>ActionController::Parameters</tt> instance with the
|
763
|
+
# results of running +block+ once for every key. This includes the keys
|
764
|
+
# from the root hash and from all nested hashes and arrays. The values are unchanged.
|
765
|
+
def deep_transform_keys(&block)
|
766
|
+
new_instance_with_inherited_permitted_status(
|
767
|
+
@parameters.deep_transform_keys(&block)
|
768
|
+
)
|
769
|
+
end
|
770
|
+
|
771
|
+
# Returns the <tt>ActionController::Parameters</tt> instance changing its keys.
|
772
|
+
# This includes the keys from the root hash and from all nested hashes and arrays.
|
773
|
+
# The values are unchanged.
|
774
|
+
def deep_transform_keys!(&block)
|
775
|
+
@parameters.deep_transform_keys!(&block)
|
776
|
+
self
|
777
|
+
end
|
778
|
+
|
679
779
|
# Deletes a key-value pair from +Parameters+ and returns the value. If
|
680
780
|
# +key+ is not found, returns +nil+ (or, with optional code block, yields
|
681
781
|
# +key+ and returns the result). Cf. +#extract!+, which returns the
|
@@ -710,6 +810,28 @@ module ActionController
|
|
710
810
|
end
|
711
811
|
alias_method :delete_if, :reject!
|
712
812
|
|
813
|
+
# Returns a new instance of <tt>ActionController::Parameters</tt> with +nil+ values removed.
|
814
|
+
def compact
|
815
|
+
new_instance_with_inherited_permitted_status(@parameters.compact)
|
816
|
+
end
|
817
|
+
|
818
|
+
# Removes all +nil+ values in place and returns +self+, or +nil+ if no changes were made.
|
819
|
+
def compact!
|
820
|
+
self if @parameters.compact!
|
821
|
+
end
|
822
|
+
|
823
|
+
# Returns a new instance of <tt>ActionController::Parameters</tt> without the blank values.
|
824
|
+
# Uses Object#blank? for determining if a value is blank.
|
825
|
+
def compact_blank
|
826
|
+
reject { |_k, v| v.blank? }
|
827
|
+
end
|
828
|
+
|
829
|
+
# Removes all blank values in place and returns self.
|
830
|
+
# Uses Object#blank? for determining if a value is blank.
|
831
|
+
def compact_blank!
|
832
|
+
reject! { |_k, v| v.blank? }
|
833
|
+
end
|
834
|
+
|
713
835
|
# Returns values that were assigned to the given +keys+. Note that all the
|
714
836
|
# +Hash+ objects will be converted to <tt>ActionController::Parameters</tt>.
|
715
837
|
def values_at(*keys)
|
@@ -756,7 +878,7 @@ module ActionController
|
|
756
878
|
end
|
757
879
|
|
758
880
|
def inspect
|
759
|
-
"
|
881
|
+
"#<#{self.class} #{@parameters} permitted: #{@permitted}>"
|
760
882
|
end
|
761
883
|
|
762
884
|
def self.hook_into_yaml_loading # :nodoc:
|
@@ -781,14 +903,14 @@ module ActionController
|
|
781
903
|
@permitted = coder.map["ivars"][:@permitted]
|
782
904
|
when "!ruby/object:ActionController::Parameters"
|
783
905
|
# YAML's Object format. Only needed because of the format
|
784
|
-
#
|
906
|
+
# backwards compatibility above, otherwise equivalent to YAML's initialization.
|
785
907
|
@parameters, @permitted = coder.map["parameters"], coder.map["permitted"]
|
786
908
|
end
|
787
909
|
end
|
788
910
|
|
789
911
|
# Returns duplicate of object including all parameters.
|
790
912
|
def deep_dup
|
791
|
-
self.class.new(@parameters.deep_dup).tap do |duplicate|
|
913
|
+
self.class.new(@parameters.deep_dup, @logging_context).tap do |duplicate|
|
792
914
|
duplicate.permitted = @permitted
|
793
915
|
end
|
794
916
|
end
|
@@ -796,17 +918,21 @@ module ActionController
|
|
796
918
|
protected
|
797
919
|
attr_reader :parameters
|
798
920
|
|
799
|
-
|
800
|
-
|
921
|
+
attr_writer :permitted
|
922
|
+
|
923
|
+
def nested_attributes?
|
924
|
+
@parameters.any? { |k, v| Parameters.nested_attribute?(k, v) }
|
801
925
|
end
|
802
926
|
|
803
|
-
def
|
804
|
-
|
927
|
+
def each_nested_attribute
|
928
|
+
hash = self.class.new
|
929
|
+
self.each { |k, v| hash[k] = yield v if Parameters.nested_attribute?(k, v) }
|
930
|
+
hash
|
805
931
|
end
|
806
932
|
|
807
933
|
private
|
808
934
|
def new_instance_with_inherited_permitted_status(hash)
|
809
|
-
self.class.new(hash).tap do |new_instance|
|
935
|
+
self.class.new(hash, @logging_context).tap do |new_instance|
|
810
936
|
new_instance.permitted = @permitted
|
811
937
|
end
|
812
938
|
end
|
@@ -837,24 +963,28 @@ module ActionController
|
|
837
963
|
when Array
|
838
964
|
return value if converted_arrays.member?(value)
|
839
965
|
converted = value.map { |_| convert_value_to_parameters(_) }
|
840
|
-
converted_arrays << converted
|
966
|
+
converted_arrays << converted.dup
|
841
967
|
converted
|
842
968
|
when Hash
|
843
|
-
self.class.new(value)
|
969
|
+
self.class.new(value, @logging_context)
|
844
970
|
else
|
845
971
|
value
|
846
972
|
end
|
847
973
|
end
|
848
974
|
|
849
|
-
def
|
975
|
+
def specify_numeric_keys?(filter)
|
976
|
+
if filter.respond_to?(:keys)
|
977
|
+
filter.keys.any? { |key| /\A-?\d+\z/.match?(key) }
|
978
|
+
end
|
979
|
+
end
|
980
|
+
|
981
|
+
def each_element(object, filter, &block)
|
850
982
|
case object
|
851
983
|
when Array
|
852
|
-
object.grep(Parameters).
|
984
|
+
object.grep(Parameters).filter_map(&block)
|
853
985
|
when Parameters
|
854
|
-
if object.
|
855
|
-
|
856
|
-
object.each { |k, v| hash[k] = yield v }
|
857
|
-
hash
|
986
|
+
if object.nested_attributes? && !specify_numeric_keys?(filter)
|
987
|
+
object.each_nested_attribute(&block)
|
858
988
|
else
|
859
989
|
yield object
|
860
990
|
end
|
@@ -867,7 +997,7 @@ module ActionController
|
|
867
997
|
case self.class.action_on_unpermitted_parameters
|
868
998
|
when :log
|
869
999
|
name = "unpermitted_parameters.action_controller"
|
870
|
-
ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys)
|
1000
|
+
ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys, context: @logging_context)
|
871
1001
|
when :raise
|
872
1002
|
raise ActionController::UnpermittedParameters.new(unpermitted_keys)
|
873
1003
|
end
|
@@ -882,7 +1012,7 @@ module ActionController
|
|
882
1012
|
# --- Filtering ----------------------------------------------------------
|
883
1013
|
#
|
884
1014
|
|
885
|
-
# This is a
|
1015
|
+
# This is a list of permitted scalar types that includes the ones
|
886
1016
|
# supported in XML and JSON requests.
|
887
1017
|
#
|
888
1018
|
# This list is in particular used to filter ordinary requests, String goes
|
@@ -909,15 +1039,28 @@ module ActionController
|
|
909
1039
|
PERMITTED_SCALAR_TYPES.any? { |type| value.is_a?(type) }
|
910
1040
|
end
|
911
1041
|
|
912
|
-
|
913
|
-
|
914
|
-
|
1042
|
+
# Adds existing keys to the params if their values are scalar.
|
1043
|
+
#
|
1044
|
+
# For example:
|
1045
|
+
#
|
1046
|
+
# puts self.keys #=> ["zipcode(90210i)"]
|
1047
|
+
# params = {}
|
1048
|
+
#
|
1049
|
+
# permitted_scalar_filter(params, "zipcode")
|
1050
|
+
#
|
1051
|
+
# puts params.keys # => ["zipcode"]
|
1052
|
+
def permitted_scalar_filter(params, permitted_key)
|
1053
|
+
permitted_key = permitted_key.to_s
|
1054
|
+
|
1055
|
+
if has_key?(permitted_key) && permitted_scalar?(self[permitted_key])
|
1056
|
+
params[permitted_key] = self[permitted_key]
|
915
1057
|
end
|
916
1058
|
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
1059
|
+
each_key do |key|
|
1060
|
+
next unless key =~ /\(\d+[if]?\)\z/
|
1061
|
+
next unless $~.pre_match == permitted_key
|
1062
|
+
|
1063
|
+
params[key] = self[key] if permitted_scalar?(self[key])
|
921
1064
|
end
|
922
1065
|
end
|
923
1066
|
|
@@ -953,7 +1096,7 @@ module ActionController
|
|
953
1096
|
end
|
954
1097
|
elsif non_scalar?(value)
|
955
1098
|
# Declaration { user: :name } or { user: [:name, :age, { address: ... }] }.
|
956
|
-
params[key] = each_element(value) do |element|
|
1099
|
+
params[key] = each_element(value, filter[key]) do |element|
|
957
1100
|
element.permit(*Array.wrap(filter[key]))
|
958
1101
|
end
|
959
1102
|
end
|
@@ -1002,8 +1145,8 @@ module ActionController
|
|
1002
1145
|
#
|
1003
1146
|
# It provides an interface for protecting attributes from end-user
|
1004
1147
|
# assignment. This makes Action Controller parameters forbidden
|
1005
|
-
# to be used in Active Model mass assignment until they have been
|
1006
|
-
#
|
1148
|
+
# to be used in Active Model mass assignment until they have been explicitly
|
1149
|
+
# enumerated.
|
1007
1150
|
#
|
1008
1151
|
# In addition, parameters can be marked as required and flow through a
|
1009
1152
|
# predefined raise/rescue flow to end up as a <tt>400 Bad Request</tt> with no
|
@@ -1039,7 +1182,7 @@ module ActionController
|
|
1039
1182
|
# end
|
1040
1183
|
#
|
1041
1184
|
# In order to use <tt>accepts_nested_attributes_for</tt> with Strong \Parameters, you
|
1042
|
-
# will need to specify which nested attributes should be
|
1185
|
+
# will need to specify which nested attributes should be permitted. You might want
|
1043
1186
|
# to allow +:id+ and +:_destroy+, see ActiveRecord::NestedAttributes for more information.
|
1044
1187
|
#
|
1045
1188
|
# class Person
|
@@ -1057,7 +1200,7 @@ module ActionController
|
|
1057
1200
|
# private
|
1058
1201
|
#
|
1059
1202
|
# def person_params
|
1060
|
-
# # It's mandatory to specify the nested attributes that should be
|
1203
|
+
# # It's mandatory to specify the nested attributes that should be permitted.
|
1061
1204
|
# # If you use `permit` with just the key that points to the nested attributes hash,
|
1062
1205
|
# # it will return an empty hash.
|
1063
1206
|
# params.require(:person).permit(:name, :age, pets_attributes: [ :id, :name, :category ])
|
@@ -1067,13 +1210,18 @@ module ActionController
|
|
1067
1210
|
# See ActionController::Parameters.require and ActionController::Parameters.permit
|
1068
1211
|
# for more information.
|
1069
1212
|
module StrongParameters
|
1070
|
-
extend ActiveSupport::Concern
|
1071
|
-
include ActiveSupport::Rescuable
|
1072
|
-
|
1073
1213
|
# Returns a new ActionController::Parameters object that
|
1074
1214
|
# has been instantiated with the <tt>request.parameters</tt>.
|
1075
1215
|
def params
|
1076
|
-
@_params ||=
|
1216
|
+
@_params ||= begin
|
1217
|
+
context = {
|
1218
|
+
controller: self.class.name,
|
1219
|
+
action: action_name,
|
1220
|
+
request: request,
|
1221
|
+
params: request.filtered_parameters
|
1222
|
+
}
|
1223
|
+
Parameters.new(request.parameters, context)
|
1224
|
+
end
|
1077
1225
|
end
|
1078
1226
|
|
1079
1227
|
# Assigns the given +value+ to the +params+ hash. If +value+
|