actionpack 7.1.5.1 → 8.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +308 -523
- data/README.rdoc +1 -1
- data/lib/abstract_controller/asset_paths.rb +6 -2
- data/lib/abstract_controller/base.rb +104 -105
- data/lib/abstract_controller/caching/fragments.rb +50 -53
- data/lib/abstract_controller/caching.rb +8 -3
- data/lib/abstract_controller/callbacks.rb +70 -62
- data/lib/abstract_controller/collector.rb +7 -7
- data/lib/abstract_controller/deprecator.rb +2 -0
- data/lib/abstract_controller/error.rb +2 -0
- data/lib/abstract_controller/helpers.rb +71 -84
- data/lib/abstract_controller/logger.rb +4 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/rendering.rb +13 -13
- data/lib/abstract_controller/translation.rb +12 -13
- data/lib/abstract_controller/url_for.rb +8 -6
- data/lib/abstract_controller.rb +2 -0
- data/lib/action_controller/api/api_rendering.rb +2 -0
- data/lib/action_controller/api.rb +76 -72
- data/lib/action_controller/base.rb +199 -126
- data/lib/action_controller/caching.rb +16 -14
- data/lib/action_controller/deprecator.rb +2 -0
- data/lib/action_controller/form_builder.rb +21 -18
- data/lib/action_controller/log_subscriber.rb +23 -2
- data/lib/action_controller/metal/allow_browser.rb +133 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
- data/lib/action_controller/metal/conditional_get.rb +217 -175
- data/lib/action_controller/metal/content_security_policy.rb +25 -24
- data/lib/action_controller/metal/cookies.rb +4 -2
- data/lib/action_controller/metal/data_streaming.rb +72 -63
- data/lib/action_controller/metal/default_headers.rb +5 -3
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
- data/lib/action_controller/metal/exceptions.rb +16 -9
- data/lib/action_controller/metal/flash.rb +13 -14
- data/lib/action_controller/metal/head.rb +15 -11
- data/lib/action_controller/metal/helpers.rb +63 -55
- data/lib/action_controller/metal/http_authentication.rb +209 -201
- data/lib/action_controller/metal/implicit_render.rb +17 -15
- data/lib/action_controller/metal/instrumentation.rb +16 -14
- data/lib/action_controller/metal/live.rb +177 -128
- data/lib/action_controller/metal/logging.rb +6 -4
- data/lib/action_controller/metal/mime_responds.rb +151 -142
- data/lib/action_controller/metal/parameter_encoding.rb +34 -32
- data/lib/action_controller/metal/params_wrapper.rb +57 -59
- data/lib/action_controller/metal/permissions_policy.rb +22 -12
- data/lib/action_controller/metal/rate_limiting.rb +92 -0
- data/lib/action_controller/metal/redirecting.rb +213 -94
- data/lib/action_controller/metal/renderers.rb +78 -57
- data/lib/action_controller/metal/rendering.rb +111 -77
- data/lib/action_controller/metal/request_forgery_protection.rb +182 -143
- data/lib/action_controller/metal/rescue.rb +20 -9
- data/lib/action_controller/metal/streaming.rb +118 -195
- data/lib/action_controller/metal/strong_parameters.rb +720 -530
- data/lib/action_controller/metal/testing.rb +2 -0
- data/lib/action_controller/metal/url_for.rb +17 -15
- data/lib/action_controller/metal.rb +86 -60
- data/lib/action_controller/railtie.rb +36 -15
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +41 -36
- data/lib/action_controller/structured_event_subscriber.rb +116 -0
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +160 -131
- data/lib/action_controller.rb +5 -1
- data/lib/action_dispatch/constants.rb +8 -0
- data/lib/action_dispatch/deprecator.rb +2 -0
- data/lib/action_dispatch/http/cache.rb +163 -35
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +54 -39
- data/lib/action_dispatch/http/filter_parameters.rb +14 -8
- data/lib/action_dispatch/http/filter_redirect.rb +22 -1
- data/lib/action_dispatch/http/headers.rb +22 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +89 -41
- data/lib/action_dispatch/http/mime_type.rb +25 -21
- data/lib/action_dispatch/http/mime_types.rb +3 -0
- data/lib/action_dispatch/http/param_builder.rb +187 -0
- data/lib/action_dispatch/http/param_error.rb +26 -0
- data/lib/action_dispatch/http/parameters.rb +14 -12
- data/lib/action_dispatch/http/permissions_policy.rb +25 -36
- data/lib/action_dispatch/http/query_parser.rb +55 -0
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +141 -92
- data/lib/action_dispatch/http/response.rb +137 -77
- data/lib/action_dispatch/http/upload.rb +18 -16
- data/lib/action_dispatch/http/url.rb +187 -89
- data/lib/action_dispatch/journey/formatter.rb +21 -9
- data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +34 -11
- data/lib/action_dispatch/journey/gtg/transition_table.rb +47 -53
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
- data/lib/action_dispatch/journey/nodes/node.rb +8 -6
- data/lib/action_dispatch/journey/parser.rb +99 -195
- data/lib/action_dispatch/journey/path/pattern.rb +4 -1
- data/lib/action_dispatch/journey/route.rb +54 -38
- data/lib/action_dispatch/journey/router/utils.rb +22 -27
- data/lib/action_dispatch/journey/router.rb +63 -83
- data/lib/action_dispatch/journey/routes.rb +11 -2
- data/lib/action_dispatch/journey/scanner.rb +46 -42
- data/lib/action_dispatch/journey/visitors.rb +57 -23
- data/lib/action_dispatch/journey/visualizer/fsm.js +4 -6
- data/lib/action_dispatch/journey.rb +2 -0
- data/lib/action_dispatch/log_subscriber.rb +7 -1
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
- data/lib/action_dispatch/middleware/callbacks.rb +3 -1
- data/lib/action_dispatch/middleware/cookies.rb +125 -106
- data/lib/action_dispatch/middleware/debug_exceptions.rb +37 -8
- data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
- data/lib/action_dispatch/middleware/debug_view.rb +13 -5
- data/lib/action_dispatch/middleware/exception_wrapper.rb +18 -23
- data/lib/action_dispatch/middleware/executor.rb +19 -4
- data/lib/action_dispatch/middleware/flash.rb +63 -51
- data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
- data/lib/action_dispatch/middleware/public_exceptions.rb +14 -12
- data/lib/action_dispatch/middleware/reloader.rb +5 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +87 -77
- data/lib/action_dispatch/middleware/request_id.rb +16 -10
- data/lib/action_dispatch/middleware/server_timing.rb +4 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +30 -8
- data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +16 -16
- data/lib/action_dispatch/middleware/ssl.rb +53 -40
- data/lib/action_dispatch/middleware/stack.rb +11 -10
- data/lib/action_dispatch/middleware/static.rb +33 -31
- data/lib/action_dispatch/middleware/templates/rescues/_copy_button.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +3 -5
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +9 -5
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +50 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
- data/lib/action_dispatch/railtie.rb +23 -3
- data/lib/action_dispatch/request/session.rb +24 -21
- data/lib/action_dispatch/request/utils.rb +11 -3
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +85 -60
- data/lib/action_dispatch/routing/mapper.rb +1031 -851
- data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
- data/lib/action_dispatch/routing/redirection.rb +47 -39
- data/lib/action_dispatch/routing/route_set.rb +79 -56
- data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
- data/lib/action_dispatch/routing/url_for.rb +130 -125
- data/lib/action_dispatch/routing.rb +150 -148
- data/lib/action_dispatch/structured_event_subscriber.rb +20 -0
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +16 -23
- data/lib/action_dispatch/system_testing/driver.rb +2 -0
- data/lib/action_dispatch/system_testing/server.rb +2 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +34 -23
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
- data/lib/action_dispatch/testing/assertion_response.rb +9 -7
- data/lib/action_dispatch/testing/assertions/response.rb +52 -25
- data/lib/action_dispatch/testing/assertions/routing.rb +168 -87
- data/lib/action_dispatch/testing/assertions.rb +2 -0
- data/lib/action_dispatch/testing/integration.rb +233 -223
- data/lib/action_dispatch/testing/request_encoder.rb +11 -9
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +11 -8
- data/lib/action_dispatch/testing/test_request.rb +3 -1
- data/lib/action_dispatch/testing/test_response.rb +27 -26
- data/lib/action_dispatch.rb +36 -32
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +17 -16
- metadata +36 -32
- data/lib/action_dispatch/journey/parser.y +0 -50
- data/lib/action_dispatch/journey/parser_extras.rb +0 -31
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "active_support/core_ext/hash/indifferent_access"
|
|
4
6
|
require "active_support/core_ext/array/wrap"
|
|
5
7
|
require "active_support/core_ext/string/filters"
|
|
@@ -8,24 +10,25 @@ require "active_support/deep_mergeable"
|
|
|
8
10
|
require "action_dispatch/http/upload"
|
|
9
11
|
require "rack/test"
|
|
10
12
|
require "stringio"
|
|
11
|
-
require "set"
|
|
12
13
|
require "yaml"
|
|
13
14
|
|
|
14
15
|
module ActionController
|
|
15
16
|
# Raised when a required parameter is missing.
|
|
16
17
|
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
18
|
+
# params = ActionController::Parameters.new(a: {})
|
|
19
|
+
# params.fetch(:b)
|
|
20
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: b
|
|
21
|
+
# params.require(:a)
|
|
22
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: a
|
|
23
|
+
# params.expect(a: [])
|
|
24
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: a
|
|
22
25
|
class ParameterMissing < KeyError
|
|
23
26
|
attr_reader :param, :keys # :nodoc:
|
|
24
27
|
|
|
25
28
|
def initialize(param, keys = nil) # :nodoc:
|
|
26
29
|
@param = param
|
|
27
30
|
@keys = keys
|
|
28
|
-
super("param is missing or the value is empty: #{param}")
|
|
31
|
+
super("param is missing or the value is empty or invalid: #{param}")
|
|
29
32
|
end
|
|
30
33
|
|
|
31
34
|
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
|
@@ -37,13 +40,22 @@ module ActionController
|
|
|
37
40
|
end
|
|
38
41
|
end
|
|
39
42
|
|
|
43
|
+
# Raised from `expect!` when an expected parameter is missing or is of an
|
|
44
|
+
# incompatible type.
|
|
45
|
+
#
|
|
46
|
+
# params = ActionController::Parameters.new(a: {})
|
|
47
|
+
# params.expect!(:a)
|
|
48
|
+
# # => ActionController::ExpectedParameterMissing: param is missing or the value is empty or invalid: a
|
|
49
|
+
class ExpectedParameterMissing < ParameterMissing
|
|
50
|
+
end
|
|
51
|
+
|
|
40
52
|
# Raised when a supplied parameter is not expected and
|
|
41
|
-
# ActionController::Parameters.action_on_unpermitted_parameters
|
|
42
|
-
#
|
|
53
|
+
# ActionController::Parameters.action_on_unpermitted_parameters is set to
|
|
54
|
+
# `:raise`.
|
|
43
55
|
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
56
|
+
# params = ActionController::Parameters.new(a: "123", b: "456")
|
|
57
|
+
# params.permit(:c)
|
|
58
|
+
# # => ActionController::UnpermittedParameters: found unpermitted parameters: :a, :b
|
|
47
59
|
class UnpermittedParameters < IndexError
|
|
48
60
|
attr_reader :params # :nodoc:
|
|
49
61
|
|
|
@@ -53,12 +65,12 @@ module ActionController
|
|
|
53
65
|
end
|
|
54
66
|
end
|
|
55
67
|
|
|
56
|
-
# Raised when a Parameters instance is not marked as permitted and
|
|
57
|
-
#
|
|
68
|
+
# Raised when a Parameters instance is not marked as permitted and an operation
|
|
69
|
+
# to transform it to hash is called.
|
|
58
70
|
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
71
|
+
# params = ActionController::Parameters.new(a: "123", b: "456")
|
|
72
|
+
# params.to_h
|
|
73
|
+
# # => ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
|
|
62
74
|
class UnfilteredParameters < ArgumentError
|
|
63
75
|
def initialize # :nodoc:
|
|
64
76
|
super("unable to convert unpermitted parameters to hash")
|
|
@@ -67,76 +79,84 @@ module ActionController
|
|
|
67
79
|
|
|
68
80
|
# Raised when initializing Parameters with keys that aren't strings or symbols.
|
|
69
81
|
#
|
|
70
|
-
#
|
|
71
|
-
#
|
|
82
|
+
# ActionController::Parameters.new(123 => 456)
|
|
83
|
+
# # => ActionController::InvalidParameterKey: all keys must be Strings or Symbols, got: Integer
|
|
72
84
|
class InvalidParameterKey < ArgumentError
|
|
73
85
|
end
|
|
74
86
|
|
|
75
|
-
#
|
|
87
|
+
# # Action Controller Parameters
|
|
76
88
|
#
|
|
77
89
|
# Allows you to choose which attributes should be permitted for mass updating
|
|
78
90
|
# and thus prevent accidentally exposing that which shouldn't be exposed.
|
|
79
|
-
# Provides two methods for this purpose: #require and #permit. The former is
|
|
80
|
-
# used to mark parameters as required. The latter is used to set the parameter
|
|
81
|
-
# as permitted and limit which attributes should be allowed for mass updating.
|
|
82
91
|
#
|
|
83
|
-
#
|
|
84
|
-
# person: {
|
|
85
|
-
# name: "Francesco",
|
|
86
|
-
# age: 22,
|
|
87
|
-
# role: "admin"
|
|
88
|
-
# }
|
|
89
|
-
# })
|
|
92
|
+
# Provides methods for filtering and requiring params:
|
|
90
93
|
#
|
|
91
|
-
#
|
|
92
|
-
#
|
|
93
|
-
#
|
|
94
|
+
# * `expect` to safely permit and require parameters in one step.
|
|
95
|
+
# * `permit` to filter params for mass assignment.
|
|
96
|
+
# * `require` to require a parameter or raise an error.
|
|
97
|
+
#
|
|
98
|
+
# Examples:
|
|
99
|
+
#
|
|
100
|
+
# params = ActionController::Parameters.new({
|
|
101
|
+
# person: {
|
|
102
|
+
# name: "Francesco",
|
|
103
|
+
# age: 22,
|
|
104
|
+
# role: "admin"
|
|
105
|
+
# }
|
|
106
|
+
# })
|
|
94
107
|
#
|
|
95
|
-
#
|
|
96
|
-
#
|
|
108
|
+
# permitted = params.expect(person: [:name, :age])
|
|
109
|
+
# permitted # => #<ActionController::Parameters {"name"=>"Francesco", "age"=>22} permitted: true>
|
|
97
110
|
#
|
|
98
|
-
#
|
|
111
|
+
# Person.first.update!(permitted)
|
|
112
|
+
# # => #<Person id: 1, name: "Francesco", age: 22, role: "user">
|
|
99
113
|
#
|
|
100
|
-
#
|
|
101
|
-
#
|
|
102
|
-
#
|
|
103
|
-
#
|
|
104
|
-
#
|
|
105
|
-
#
|
|
106
|
-
#
|
|
107
|
-
#
|
|
108
|
-
#
|
|
114
|
+
# Parameters provides two options that control the top-level behavior of new
|
|
115
|
+
# instances:
|
|
116
|
+
#
|
|
117
|
+
# * `permit_all_parameters` - If it's `true`, all the parameters will be
|
|
118
|
+
# permitted by default. The default is `false`.
|
|
119
|
+
# * `action_on_unpermitted_parameters` - Controls behavior when parameters
|
|
120
|
+
# that are not explicitly permitted are found. The default value is `:log`
|
|
121
|
+
# in test and development environments, `false` otherwise. The values can
|
|
122
|
+
# be:
|
|
123
|
+
# * `false` to take no action.
|
|
124
|
+
# * `:log` to emit an `ActiveSupport::Notifications.instrument` event on
|
|
125
|
+
# the `unpermitted_parameters.action_controller` topic and log at the
|
|
126
|
+
# DEBUG level.
|
|
127
|
+
# * `:raise` to raise an ActionController::UnpermittedParameters
|
|
128
|
+
# exception.
|
|
109
129
|
#
|
|
110
130
|
# Examples:
|
|
111
131
|
#
|
|
112
|
-
#
|
|
113
|
-
#
|
|
132
|
+
# params = ActionController::Parameters.new
|
|
133
|
+
# params.permitted? # => false
|
|
114
134
|
#
|
|
115
|
-
#
|
|
135
|
+
# ActionController::Parameters.permit_all_parameters = true
|
|
116
136
|
#
|
|
117
|
-
#
|
|
118
|
-
#
|
|
137
|
+
# params = ActionController::Parameters.new
|
|
138
|
+
# params.permitted? # => true
|
|
119
139
|
#
|
|
120
|
-
#
|
|
121
|
-
#
|
|
122
|
-
#
|
|
140
|
+
# params = ActionController::Parameters.new(a: "123", b: "456")
|
|
141
|
+
# params.permit(:c)
|
|
142
|
+
# # => #<ActionController::Parameters {} permitted: true>
|
|
123
143
|
#
|
|
124
|
-
#
|
|
144
|
+
# ActionController::Parameters.action_on_unpermitted_parameters = :raise
|
|
125
145
|
#
|
|
126
|
-
#
|
|
127
|
-
#
|
|
128
|
-
#
|
|
146
|
+
# params = ActionController::Parameters.new(a: "123", b: "456")
|
|
147
|
+
# params.permit(:c)
|
|
148
|
+
# # => ActionController::UnpermittedParameters: found unpermitted keys: a, b
|
|
129
149
|
#
|
|
130
150
|
# Please note that these options *are not thread-safe*. In a multi-threaded
|
|
131
151
|
# environment they should only be set once at boot-time and never mutated at
|
|
132
152
|
# runtime.
|
|
133
153
|
#
|
|
134
|
-
# You can fetch values of
|
|
135
|
-
#
|
|
154
|
+
# You can fetch values of `ActionController::Parameters` using either `:key` or
|
|
155
|
+
# `"key"`.
|
|
136
156
|
#
|
|
137
|
-
#
|
|
138
|
-
#
|
|
139
|
-
#
|
|
157
|
+
# params = ActionController::Parameters.new(key: "value")
|
|
158
|
+
# params[:key] # => "value"
|
|
159
|
+
# params["key"] # => "value"
|
|
140
160
|
class Parameters
|
|
141
161
|
include ActiveSupport::DeepMergeable
|
|
142
162
|
|
|
@@ -148,12 +168,13 @@ module ActionController
|
|
|
148
168
|
# :method: deep_merge
|
|
149
169
|
#
|
|
150
170
|
# :call-seq:
|
|
151
|
-
#
|
|
171
|
+
# deep_merge(other_hash, &block)
|
|
152
172
|
#
|
|
153
|
-
# Returns a new
|
|
173
|
+
# Returns a new `ActionController::Parameters` instance with `self` and
|
|
174
|
+
# `other_hash` merged recursively.
|
|
154
175
|
#
|
|
155
|
-
# Like with
|
|
156
|
-
#
|
|
176
|
+
# Like with `Hash#merge` in the standard library, a block can be provided to
|
|
177
|
+
# merge values.
|
|
157
178
|
#
|
|
158
179
|
#--
|
|
159
180
|
# Implemented by ActiveSupport::DeepMergeable#deep_merge.
|
|
@@ -162,9 +183,9 @@ module ActionController
|
|
|
162
183
|
# :method: deep_merge!
|
|
163
184
|
#
|
|
164
185
|
# :call-seq:
|
|
165
|
-
#
|
|
186
|
+
# deep_merge!(other_hash, &block)
|
|
166
187
|
#
|
|
167
|
-
# Same as
|
|
188
|
+
# Same as `#deep_merge`, but modifies `self`.
|
|
168
189
|
#
|
|
169
190
|
#--
|
|
170
191
|
# Implemented by ActiveSupport::DeepMergeable#deep_merge!.
|
|
@@ -173,7 +194,7 @@ module ActionController
|
|
|
173
194
|
# :method: as_json
|
|
174
195
|
#
|
|
175
196
|
# :call-seq:
|
|
176
|
-
#
|
|
197
|
+
# as_json(options=nil)
|
|
177
198
|
#
|
|
178
199
|
# Returns a hash that can be used as the JSON representation for the parameters.
|
|
179
200
|
|
|
@@ -181,16 +202,16 @@ module ActionController
|
|
|
181
202
|
# :method: each_key
|
|
182
203
|
#
|
|
183
204
|
# :call-seq:
|
|
184
|
-
#
|
|
205
|
+
# each_key(&block)
|
|
185
206
|
#
|
|
186
|
-
# Calls block once for each key in the parameters, passing the key.
|
|
187
|
-
#
|
|
207
|
+
# Calls block once for each key in the parameters, passing the key. If no block
|
|
208
|
+
# is given, an enumerator is returned instead.
|
|
188
209
|
|
|
189
210
|
##
|
|
190
211
|
# :method: empty?
|
|
191
212
|
#
|
|
192
213
|
# :call-seq:
|
|
193
|
-
#
|
|
214
|
+
# empty?()
|
|
194
215
|
#
|
|
195
216
|
# Returns true if the parameters have no key/value pairs.
|
|
196
217
|
|
|
@@ -198,7 +219,7 @@ module ActionController
|
|
|
198
219
|
# :method: exclude?
|
|
199
220
|
#
|
|
200
221
|
# :call-seq:
|
|
201
|
-
#
|
|
222
|
+
# exclude?(key)
|
|
202
223
|
#
|
|
203
224
|
# Returns true if the given key is not present in the parameters.
|
|
204
225
|
|
|
@@ -206,7 +227,7 @@ module ActionController
|
|
|
206
227
|
# :method: include?
|
|
207
228
|
#
|
|
208
229
|
# :call-seq:
|
|
209
|
-
#
|
|
230
|
+
# include?(key)
|
|
210
231
|
#
|
|
211
232
|
# Returns true if the given key is present in the parameters.
|
|
212
233
|
|
|
@@ -214,7 +235,7 @@ module ActionController
|
|
|
214
235
|
# :method: keys
|
|
215
236
|
#
|
|
216
237
|
# :call-seq:
|
|
217
|
-
#
|
|
238
|
+
# keys()
|
|
218
239
|
#
|
|
219
240
|
# Returns a new array of the keys of the parameters.
|
|
220
241
|
|
|
@@ -222,7 +243,7 @@ module ActionController
|
|
|
222
243
|
# :method: to_s
|
|
223
244
|
#
|
|
224
245
|
# :call-seq:
|
|
225
|
-
#
|
|
246
|
+
# to_s()
|
|
226
247
|
#
|
|
227
248
|
# Returns the content of the parameters as a string.
|
|
228
249
|
|
|
@@ -233,39 +254,36 @@ module ActionController
|
|
|
233
254
|
alias_method :key?, :include?
|
|
234
255
|
alias_method :member?, :include?
|
|
235
256
|
|
|
236
|
-
# By default, never raise an UnpermittedParameters exception if these
|
|
237
|
-
#
|
|
238
|
-
#
|
|
239
|
-
#
|
|
240
|
-
# config. For instance:
|
|
257
|
+
# By default, never raise an UnpermittedParameters exception if these params are
|
|
258
|
+
# present. The default includes both 'controller' and 'action' because they are
|
|
259
|
+
# added by Rails and should be of no concern. One way to change these is to
|
|
260
|
+
# specify `always_permitted_parameters` in your config. For instance:
|
|
241
261
|
#
|
|
242
|
-
#
|
|
262
|
+
# config.action_controller.always_permitted_parameters = %w( controller action format )
|
|
243
263
|
cattr_accessor :always_permitted_parameters, default: %w( controller action )
|
|
244
264
|
|
|
245
|
-
cattr_accessor :allow_deprecated_parameters_hash_equality, default: true, instance_accessor: false
|
|
246
|
-
|
|
247
265
|
class << self
|
|
248
266
|
def nested_attribute?(key, value) # :nodoc:
|
|
249
267
|
/\A-?\d+\z/.match?(key) && (value.is_a?(Hash) || value.is_a?(Parameters))
|
|
250
268
|
end
|
|
251
269
|
end
|
|
252
270
|
|
|
253
|
-
# Returns a new
|
|
254
|
-
#
|
|
255
|
-
#
|
|
271
|
+
# Returns a new `ActionController::Parameters` instance. Also, sets the
|
|
272
|
+
# `permitted` attribute to the default value of
|
|
273
|
+
# `ActionController::Parameters.permit_all_parameters`.
|
|
256
274
|
#
|
|
257
|
-
#
|
|
258
|
-
#
|
|
275
|
+
# class Person < ActiveRecord::Base
|
|
276
|
+
# end
|
|
259
277
|
#
|
|
260
|
-
#
|
|
261
|
-
#
|
|
262
|
-
#
|
|
278
|
+
# params = ActionController::Parameters.new(name: "Francesco")
|
|
279
|
+
# params.permitted? # => false
|
|
280
|
+
# Person.new(params) # => ActiveModel::ForbiddenAttributesError
|
|
263
281
|
#
|
|
264
|
-
#
|
|
282
|
+
# ActionController::Parameters.permit_all_parameters = true
|
|
265
283
|
#
|
|
266
|
-
#
|
|
267
|
-
#
|
|
268
|
-
#
|
|
284
|
+
# params = ActionController::Parameters.new(name: "Francesco")
|
|
285
|
+
# params.permitted? # => true
|
|
286
|
+
# Person.new(params) # => #<Person id: nil, name: "Francesco">
|
|
269
287
|
def initialize(parameters = {}, logging_context = {})
|
|
270
288
|
parameters.each_key do |key|
|
|
271
289
|
unless key.is_a?(String) || key.is_a?(Symbol)
|
|
@@ -278,26 +296,13 @@ module ActionController
|
|
|
278
296
|
@permitted = self.class.permit_all_parameters
|
|
279
297
|
end
|
|
280
298
|
|
|
281
|
-
# Returns true if another
|
|
299
|
+
# Returns true if another `Parameters` object contains the same content and
|
|
282
300
|
# permitted flag.
|
|
283
301
|
def ==(other)
|
|
284
302
|
if other.respond_to?(:permitted?)
|
|
285
303
|
permitted? == other.permitted? && parameters == other.parameters
|
|
286
304
|
else
|
|
287
|
-
|
|
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
|
|
305
|
+
super
|
|
301
306
|
end
|
|
302
307
|
end
|
|
303
308
|
|
|
@@ -311,18 +316,18 @@ module ActionController
|
|
|
311
316
|
[self.class, @parameters, @permitted].hash
|
|
312
317
|
end
|
|
313
318
|
|
|
314
|
-
# Returns a safe ActiveSupport::HashWithIndifferentAccess
|
|
315
|
-
#
|
|
319
|
+
# Returns a safe ActiveSupport::HashWithIndifferentAccess representation of the
|
|
320
|
+
# parameters with all unpermitted keys removed.
|
|
316
321
|
#
|
|
317
|
-
#
|
|
318
|
-
#
|
|
319
|
-
#
|
|
320
|
-
#
|
|
321
|
-
#
|
|
322
|
-
#
|
|
322
|
+
# params = ActionController::Parameters.new({
|
|
323
|
+
# name: "Senjougahara Hitagi",
|
|
324
|
+
# oddity: "Heavy stone crab"
|
|
325
|
+
# })
|
|
326
|
+
# params.to_h
|
|
327
|
+
# # => ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
|
|
323
328
|
#
|
|
324
|
-
#
|
|
325
|
-
#
|
|
329
|
+
# safe_params = params.permit(:name)
|
|
330
|
+
# safe_params.to_h # => {"name"=>"Senjougahara Hitagi"}
|
|
326
331
|
def to_h(&block)
|
|
327
332
|
if permitted?
|
|
328
333
|
convert_parameters_to_hashes(@parameters, :to_h, &block)
|
|
@@ -331,18 +336,18 @@ module ActionController
|
|
|
331
336
|
end
|
|
332
337
|
end
|
|
333
338
|
|
|
334
|
-
# Returns a safe
|
|
335
|
-
#
|
|
339
|
+
# Returns a safe `Hash` representation of the parameters with all unpermitted
|
|
340
|
+
# keys removed.
|
|
336
341
|
#
|
|
337
|
-
#
|
|
338
|
-
#
|
|
339
|
-
#
|
|
340
|
-
#
|
|
341
|
-
#
|
|
342
|
-
#
|
|
342
|
+
# params = ActionController::Parameters.new({
|
|
343
|
+
# name: "Senjougahara Hitagi",
|
|
344
|
+
# oddity: "Heavy stone crab"
|
|
345
|
+
# })
|
|
346
|
+
# params.to_hash
|
|
347
|
+
# # => ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
|
|
343
348
|
#
|
|
344
|
-
#
|
|
345
|
-
#
|
|
349
|
+
# safe_params = params.permit(:name)
|
|
350
|
+
# safe_params.to_hash # => {"name"=>"Senjougahara Hitagi"}
|
|
346
351
|
def to_hash
|
|
347
352
|
to_h.to_hash
|
|
348
353
|
end
|
|
@@ -350,29 +355,29 @@ module ActionController
|
|
|
350
355
|
# Returns a string representation of the receiver suitable for use as a URL
|
|
351
356
|
# query string:
|
|
352
357
|
#
|
|
353
|
-
#
|
|
354
|
-
#
|
|
355
|
-
#
|
|
356
|
-
#
|
|
357
|
-
#
|
|
358
|
-
#
|
|
358
|
+
# params = ActionController::Parameters.new({
|
|
359
|
+
# name: "David",
|
|
360
|
+
# nationality: "Danish"
|
|
361
|
+
# })
|
|
362
|
+
# params.to_query
|
|
363
|
+
# # => ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
|
|
359
364
|
#
|
|
360
|
-
#
|
|
361
|
-
#
|
|
362
|
-
#
|
|
365
|
+
# safe_params = params.permit(:name, :nationality)
|
|
366
|
+
# safe_params.to_query
|
|
367
|
+
# # => "name=David&nationality=Danish"
|
|
363
368
|
#
|
|
364
369
|
# An optional namespace can be passed to enclose key names:
|
|
365
370
|
#
|
|
366
|
-
#
|
|
367
|
-
#
|
|
368
|
-
#
|
|
369
|
-
#
|
|
370
|
-
#
|
|
371
|
-
#
|
|
372
|
-
#
|
|
371
|
+
# params = ActionController::Parameters.new({
|
|
372
|
+
# name: "David",
|
|
373
|
+
# nationality: "Danish"
|
|
374
|
+
# })
|
|
375
|
+
# safe_params = params.permit(:name, :nationality)
|
|
376
|
+
# safe_params.to_query("user")
|
|
377
|
+
# # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
|
|
373
378
|
#
|
|
374
|
-
# The string pairs
|
|
375
|
-
#
|
|
379
|
+
# The string pairs `"key=value"` that conform the query string are sorted
|
|
380
|
+
# lexicographically in ascending order.
|
|
376
381
|
def to_query(*args)
|
|
377
382
|
to_h.to_query(*args)
|
|
378
383
|
end
|
|
@@ -381,19 +386,19 @@ module ActionController
|
|
|
381
386
|
# Returns an unsafe, unfiltered ActiveSupport::HashWithIndifferentAccess
|
|
382
387
|
# representation of the parameters.
|
|
383
388
|
#
|
|
384
|
-
#
|
|
385
|
-
#
|
|
386
|
-
#
|
|
387
|
-
#
|
|
388
|
-
#
|
|
389
|
-
#
|
|
389
|
+
# params = ActionController::Parameters.new({
|
|
390
|
+
# name: "Senjougahara Hitagi",
|
|
391
|
+
# oddity: "Heavy stone crab"
|
|
392
|
+
# })
|
|
393
|
+
# params.to_unsafe_h
|
|
394
|
+
# # => {"name"=>"Senjougahara Hitagi", "oddity" => "Heavy stone crab"}
|
|
390
395
|
def to_unsafe_h
|
|
391
396
|
convert_parameters_to_hashes(@parameters, :to_unsafe_h)
|
|
392
397
|
end
|
|
393
398
|
alias_method :to_unsafe_hash, :to_unsafe_h
|
|
394
399
|
|
|
395
|
-
# Convert all hashes in values into parameters, then yield each pair in
|
|
396
|
-
#
|
|
400
|
+
# Convert all hashes in values into parameters, then yield each pair in the same
|
|
401
|
+
# way as `Hash#each_pair`.
|
|
397
402
|
def each_pair(&block)
|
|
398
403
|
return to_enum(__callee__) unless block_given?
|
|
399
404
|
@parameters.each_pair do |key, value|
|
|
@@ -404,8 +409,8 @@ module ActionController
|
|
|
404
409
|
end
|
|
405
410
|
alias_method :each, :each_pair
|
|
406
411
|
|
|
407
|
-
# Convert all hashes in values into parameters, then yield each value in
|
|
408
|
-
#
|
|
412
|
+
# Convert all hashes in values into parameters, then yield each value in the
|
|
413
|
+
# same way as `Hash#each_value`.
|
|
409
414
|
def each_value(&block)
|
|
410
415
|
return to_enum(:each_value) unless block_given?
|
|
411
416
|
@parameters.each_pair do |key, value|
|
|
@@ -421,38 +426,38 @@ module ActionController
|
|
|
421
426
|
end
|
|
422
427
|
|
|
423
428
|
# Attribute that keeps track of converted arrays, if any, to avoid double
|
|
424
|
-
# looping in the common use case permit + mass-assignment. Defined in a
|
|
425
|
-
#
|
|
429
|
+
# looping in the common use case permit + mass-assignment. Defined in a method
|
|
430
|
+
# to instantiate it only if needed.
|
|
426
431
|
#
|
|
427
|
-
#
|
|
428
|
-
#
|
|
429
|
-
#
|
|
432
|
+
# Testing membership still loops, but it's going to be faster than our own loop
|
|
433
|
+
# that converts values. Also, we are not going to build a new array object per
|
|
434
|
+
# fetch.
|
|
430
435
|
def converted_arrays
|
|
431
436
|
@converted_arrays ||= Set.new
|
|
432
437
|
end
|
|
433
438
|
|
|
434
|
-
# Returns
|
|
439
|
+
# Returns `true` if the parameter is permitted, `false` otherwise.
|
|
435
440
|
#
|
|
436
|
-
#
|
|
437
|
-
#
|
|
438
|
-
#
|
|
439
|
-
#
|
|
441
|
+
# params = ActionController::Parameters.new
|
|
442
|
+
# params.permitted? # => false
|
|
443
|
+
# params.permit!
|
|
444
|
+
# params.permitted? # => true
|
|
440
445
|
def permitted?
|
|
441
446
|
@permitted
|
|
442
447
|
end
|
|
443
448
|
|
|
444
|
-
# Sets the
|
|
445
|
-
#
|
|
449
|
+
# Sets the `permitted` attribute to `true`. This can be used to pass mass
|
|
450
|
+
# assignment. Returns `self`.
|
|
446
451
|
#
|
|
447
|
-
#
|
|
448
|
-
#
|
|
452
|
+
# class Person < ActiveRecord::Base
|
|
453
|
+
# end
|
|
449
454
|
#
|
|
450
|
-
#
|
|
451
|
-
#
|
|
452
|
-
#
|
|
453
|
-
#
|
|
454
|
-
#
|
|
455
|
-
#
|
|
455
|
+
# params = ActionController::Parameters.new(name: "Francesco")
|
|
456
|
+
# params.permitted? # => false
|
|
457
|
+
# Person.new(params) # => ActiveModel::ForbiddenAttributesError
|
|
458
|
+
# params.permit!
|
|
459
|
+
# params.permitted? # => true
|
|
460
|
+
# Person.new(params) # => #<Person id: nil, name: "Francesco">
|
|
456
461
|
def permit!
|
|
457
462
|
each_pair do |key, value|
|
|
458
463
|
Array.wrap(value).flatten.each do |v|
|
|
@@ -466,54 +471,51 @@ module ActionController
|
|
|
466
471
|
|
|
467
472
|
# This method accepts both a single key and an array of keys.
|
|
468
473
|
#
|
|
469
|
-
# When passed a single key, if it exists and its associated value is
|
|
470
|
-
#
|
|
474
|
+
# When passed a single key, if it exists and its associated value is either
|
|
475
|
+
# present or the singleton `false`, returns said value:
|
|
471
476
|
#
|
|
472
|
-
#
|
|
473
|
-
#
|
|
477
|
+
# ActionController::Parameters.new(person: { name: "Francesco" }).require(:person)
|
|
478
|
+
# # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
|
474
479
|
#
|
|
475
480
|
# Otherwise raises ActionController::ParameterMissing:
|
|
476
481
|
#
|
|
477
|
-
#
|
|
478
|
-
#
|
|
482
|
+
# ActionController::Parameters.new.require(:person)
|
|
483
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty or invalid: person
|
|
479
484
|
#
|
|
480
|
-
#
|
|
481
|
-
#
|
|
485
|
+
# ActionController::Parameters.new(person: nil).require(:person)
|
|
486
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty or invalid: person
|
|
482
487
|
#
|
|
483
|
-
#
|
|
484
|
-
#
|
|
488
|
+
# ActionController::Parameters.new(person: "\t").require(:person)
|
|
489
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty or invalid: person
|
|
485
490
|
#
|
|
486
|
-
#
|
|
487
|
-
#
|
|
491
|
+
# ActionController::Parameters.new(person: {}).require(:person)
|
|
492
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty or invalid: person
|
|
488
493
|
#
|
|
489
|
-
# When given an array of keys, the method tries to require each one of them
|
|
490
|
-
#
|
|
491
|
-
# returned:
|
|
494
|
+
# When given an array of keys, the method tries to require each one of them in
|
|
495
|
+
# order. If it succeeds, an array with the respective return values is returned:
|
|
492
496
|
#
|
|
493
|
-
#
|
|
494
|
-
#
|
|
497
|
+
# params = ActionController::Parameters.new(user: { ... }, profile: { ... })
|
|
498
|
+
# user_params, profile_params = params.require([:user, :profile])
|
|
495
499
|
#
|
|
496
500
|
# Otherwise, the method re-raises the first exception found:
|
|
497
501
|
#
|
|
498
|
-
#
|
|
499
|
-
#
|
|
500
|
-
#
|
|
502
|
+
# params = ActionController::Parameters.new(user: {}, profile: {})
|
|
503
|
+
# user_params, profile_params = params.require([:user, :profile])
|
|
504
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty or invalid: user
|
|
501
505
|
#
|
|
502
|
-
#
|
|
506
|
+
# This method is not recommended for fetching terminal values because it does
|
|
507
|
+
# not permit the values. For example, this can cause problems:
|
|
503
508
|
#
|
|
504
|
-
#
|
|
505
|
-
#
|
|
506
|
-
#
|
|
509
|
+
# # CAREFUL
|
|
510
|
+
# params = ActionController::Parameters.new(person: { name: "Finn" })
|
|
511
|
+
# name = params.require(:person).require(:name) # CAREFUL
|
|
507
512
|
#
|
|
508
|
-
#
|
|
513
|
+
# It is recommended to use `expect` instead:
|
|
509
514
|
#
|
|
510
|
-
#
|
|
511
|
-
#
|
|
512
|
-
# person_params.require(:name) # SAFER
|
|
515
|
+
# def person_params
|
|
516
|
+
# params.expect(person: :name).require(:name)
|
|
513
517
|
# end
|
|
514
|
-
# end
|
|
515
518
|
#
|
|
516
|
-
# for example.
|
|
517
519
|
def require(key)
|
|
518
520
|
return key.map { |k| require(k) } if key.is_a?(Array)
|
|
519
521
|
value = self[key]
|
|
@@ -526,165 +528,295 @@ module ActionController
|
|
|
526
528
|
|
|
527
529
|
alias :required :require
|
|
528
530
|
|
|
529
|
-
# Returns a new
|
|
530
|
-
#
|
|
531
|
-
#
|
|
532
|
-
#
|
|
531
|
+
# Returns a new `ActionController::Parameters` instance that includes only the
|
|
532
|
+
# given `filters` and sets the `permitted` attribute for the object to `true`.
|
|
533
|
+
# This is useful for limiting which attributes should be allowed for mass
|
|
534
|
+
# updating.
|
|
533
535
|
#
|
|
534
|
-
#
|
|
535
|
-
#
|
|
536
|
-
#
|
|
537
|
-
#
|
|
538
|
-
#
|
|
539
|
-
#
|
|
536
|
+
# params = ActionController::Parameters.new(name: "Francesco", age: 22, role: "admin")
|
|
537
|
+
# permitted = params.permit(:name, :age)
|
|
538
|
+
# permitted.permitted? # => true
|
|
539
|
+
# permitted.has_key?(:name) # => true
|
|
540
|
+
# permitted.has_key?(:age) # => true
|
|
541
|
+
# permitted.has_key?(:role) # => false
|
|
540
542
|
#
|
|
541
543
|
# Only permitted scalars pass the filter. For example, given
|
|
542
544
|
#
|
|
543
|
-
#
|
|
544
|
-
#
|
|
545
|
-
#
|
|
546
|
-
#
|
|
547
|
-
#
|
|
548
|
-
#
|
|
549
|
-
#
|
|
550
|
-
#
|
|
551
|
-
#
|
|
552
|
-
#
|
|
553
|
-
#
|
|
554
|
-
#
|
|
555
|
-
#
|
|
556
|
-
#
|
|
557
|
-
#
|
|
558
|
-
#
|
|
559
|
-
#
|
|
560
|
-
#
|
|
561
|
-
#
|
|
562
|
-
#
|
|
563
|
-
#
|
|
564
|
-
#
|
|
565
|
-
#
|
|
566
|
-
#
|
|
567
|
-
#
|
|
568
|
-
#
|
|
569
|
-
#
|
|
570
|
-
#
|
|
571
|
-
#
|
|
572
|
-
#
|
|
573
|
-
#
|
|
574
|
-
#
|
|
575
|
-
# }]
|
|
576
|
-
# }
|
|
577
|
-
# })
|
|
578
|
-
#
|
|
579
|
-
# permitted = params.permit(person: [ :name, { pets: :name } ])
|
|
580
|
-
# permitted.permitted? # => true
|
|
581
|
-
# permitted[:person][:name] # => "Francesco"
|
|
582
|
-
# permitted[:person][:age] # => nil
|
|
583
|
-
# permitted[:person][:pets][0][:name] # => "Purplish"
|
|
584
|
-
# permitted[:person][:pets][0][:category] # => nil
|
|
585
|
-
#
|
|
586
|
-
# Note that if you use +permit+ in a key that points to a hash,
|
|
587
|
-
# it won't allow all the hash. You also need to specify which
|
|
588
|
-
# attributes inside the hash should be permitted.
|
|
589
|
-
#
|
|
590
|
-
# params = ActionController::Parameters.new({
|
|
591
|
-
# person: {
|
|
592
|
-
# contact: {
|
|
593
|
-
# email: "none@test.com",
|
|
594
|
-
# phone: "555-1234"
|
|
545
|
+
# params.permit(:name)
|
|
546
|
+
#
|
|
547
|
+
# `:name` passes if it is a key of `params` whose associated value is of type
|
|
548
|
+
# `String`, `Symbol`, `NilClass`, `Numeric`, `TrueClass`, `FalseClass`, `Date`,
|
|
549
|
+
# `Time`, `DateTime`, `StringIO`, `IO`, ActionDispatch::Http::UploadedFile or
|
|
550
|
+
# `Rack::Test::UploadedFile`. Otherwise, the key `:name` is filtered out.
|
|
551
|
+
#
|
|
552
|
+
# You may declare that the parameter should be an array of permitted scalars by
|
|
553
|
+
# mapping it to an empty array:
|
|
554
|
+
#
|
|
555
|
+
# params = ActionController::Parameters.new(tags: ["rails", "parameters"])
|
|
556
|
+
# params.permit(tags: [])
|
|
557
|
+
#
|
|
558
|
+
# Sometimes it is not possible or convenient to declare the valid keys of a hash
|
|
559
|
+
# parameter or its internal structure. Just map to an empty hash:
|
|
560
|
+
#
|
|
561
|
+
# params.permit(preferences: {})
|
|
562
|
+
#
|
|
563
|
+
# Be careful because this opens the door to arbitrary input. In this case,
|
|
564
|
+
# `permit` ensures values in the returned structure are permitted scalars and
|
|
565
|
+
# filters out anything else.
|
|
566
|
+
#
|
|
567
|
+
# You can also use `permit` on nested parameters:
|
|
568
|
+
#
|
|
569
|
+
# params = ActionController::Parameters.new({
|
|
570
|
+
# person: {
|
|
571
|
+
# name: "Francesco",
|
|
572
|
+
# age: 22,
|
|
573
|
+
# pets: [{
|
|
574
|
+
# name: "Purplish",
|
|
575
|
+
# category: "dogs"
|
|
576
|
+
# }]
|
|
595
577
|
# }
|
|
596
|
-
# }
|
|
597
|
-
#
|
|
598
|
-
#
|
|
599
|
-
#
|
|
600
|
-
#
|
|
601
|
-
#
|
|
602
|
-
#
|
|
603
|
-
#
|
|
604
|
-
#
|
|
605
|
-
#
|
|
606
|
-
#
|
|
607
|
-
#
|
|
608
|
-
#
|
|
609
|
-
#
|
|
610
|
-
#
|
|
611
|
-
#
|
|
612
|
-
#
|
|
613
|
-
#
|
|
614
|
-
#
|
|
615
|
-
#
|
|
616
|
-
#
|
|
617
|
-
#
|
|
618
|
-
#
|
|
619
|
-
#
|
|
620
|
-
#
|
|
621
|
-
#
|
|
622
|
-
#
|
|
623
|
-
#
|
|
624
|
-
#
|
|
625
|
-
#
|
|
626
|
-
#
|
|
627
|
-
#
|
|
628
|
-
#
|
|
629
|
-
#
|
|
630
|
-
#
|
|
631
|
-
#
|
|
632
|
-
#
|
|
633
|
-
#
|
|
634
|
-
#
|
|
635
|
-
#
|
|
636
|
-
#
|
|
637
|
-
#
|
|
638
|
-
#
|
|
639
|
-
#
|
|
640
|
-
#
|
|
641
|
-
#
|
|
578
|
+
# })
|
|
579
|
+
#
|
|
580
|
+
# permitted = params.permit(person: [ :name, { pets: :name } ])
|
|
581
|
+
# permitted.permitted? # => true
|
|
582
|
+
# permitted[:person][:name] # => "Francesco"
|
|
583
|
+
# permitted[:person][:age] # => nil
|
|
584
|
+
# permitted[:person][:pets][0][:name] # => "Purplish"
|
|
585
|
+
# permitted[:person][:pets][0][:category] # => nil
|
|
586
|
+
#
|
|
587
|
+
# This has the added benefit of rejecting user-modified inputs that send a
|
|
588
|
+
# string when a hash is expected.
|
|
589
|
+
#
|
|
590
|
+
# When followed by `require`, you can both filter and require parameters
|
|
591
|
+
# following the typical pattern of a Rails form. The `expect` method was
|
|
592
|
+
# made specifically for this use case and is the recommended way to require
|
|
593
|
+
# and permit parameters.
|
|
594
|
+
#
|
|
595
|
+
# permitted = params.expect(person: [:name, :age])
|
|
596
|
+
#
|
|
597
|
+
# When using `permit` and `require` separately, pay careful attention to the
|
|
598
|
+
# order of the method calls.
|
|
599
|
+
#
|
|
600
|
+
# params = ActionController::Parameters.new(person: { name: "Martin", age: 40, role: "admin" })
|
|
601
|
+
# permitted = params.permit(person: [:name, :age]).require(:person) # correct
|
|
602
|
+
#
|
|
603
|
+
# When require is used first, it is possible for users of your application to
|
|
604
|
+
# trigger a NoMethodError when the user, for example, sends a string for :person.
|
|
605
|
+
#
|
|
606
|
+
# params = ActionController::Parameters.new(person: "tampered")
|
|
607
|
+
# permitted = params.require(:person).permit(:name, :age) # not recommended
|
|
608
|
+
# # => NoMethodError: undefined method `permit' for an instance of String
|
|
609
|
+
#
|
|
610
|
+
# Note that if you use `permit` in a key that points to a hash, it won't allow
|
|
611
|
+
# all the hash. You also need to specify which attributes inside the hash should
|
|
612
|
+
# be permitted.
|
|
613
|
+
#
|
|
614
|
+
# params = ActionController::Parameters.new({
|
|
615
|
+
# person: {
|
|
616
|
+
# contact: {
|
|
617
|
+
# email: "none@test.com",
|
|
618
|
+
# phone: "555-1234"
|
|
619
|
+
# }
|
|
620
|
+
# }
|
|
621
|
+
# })
|
|
622
|
+
#
|
|
623
|
+
# params.permit(person: :contact).require(:person)
|
|
624
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: person
|
|
625
|
+
#
|
|
626
|
+
# params.permit(person: { contact: :phone }).require(:person)
|
|
627
|
+
# # => #<ActionController::Parameters {"contact"=>#<ActionController::Parameters {"phone"=>"555-1234"} permitted: true>} permitted: true>
|
|
628
|
+
#
|
|
629
|
+
# params.permit(person: { contact: [ :email, :phone ] }).require(:person)
|
|
630
|
+
# # => #<ActionController::Parameters {"contact"=>#<ActionController::Parameters {"email"=>"none@test.com", "phone"=>"555-1234"} permitted: true>} permitted: true>
|
|
631
|
+
#
|
|
632
|
+
# If your parameters specify multiple parameters indexed by a number, you can
|
|
633
|
+
# permit each set of parameters under the numeric key to be the same using the
|
|
634
|
+
# same syntax as permitting a single item.
|
|
635
|
+
#
|
|
636
|
+
# params = ActionController::Parameters.new({
|
|
637
|
+
# person: {
|
|
638
|
+
# '0': {
|
|
639
|
+
# email: "none@test.com",
|
|
640
|
+
# phone: "555-1234"
|
|
641
|
+
# },
|
|
642
|
+
# '1': {
|
|
643
|
+
# email: "nothing@test.com",
|
|
644
|
+
# phone: "555-6789"
|
|
645
|
+
# },
|
|
646
|
+
# }
|
|
647
|
+
# })
|
|
648
|
+
# params.permit(person: [:email]).to_h
|
|
649
|
+
# # => {"person"=>{"0"=>{"email"=>"none@test.com"}, "1"=>{"email"=>"nothing@test.com"}}}
|
|
650
|
+
#
|
|
651
|
+
# If you want to specify what keys you want from each numeric key, you can
|
|
652
|
+
# instead specify each one individually
|
|
653
|
+
#
|
|
654
|
+
# params = ActionController::Parameters.new({
|
|
655
|
+
# person: {
|
|
656
|
+
# '0': {
|
|
657
|
+
# email: "none@test.com",
|
|
658
|
+
# phone: "555-1234"
|
|
659
|
+
# },
|
|
660
|
+
# '1': {
|
|
661
|
+
# email: "nothing@test.com",
|
|
662
|
+
# phone: "555-6789"
|
|
663
|
+
# },
|
|
664
|
+
# }
|
|
665
|
+
# })
|
|
666
|
+
# params.permit(person: { '0': [:email], '1': [:phone]}).to_h
|
|
667
|
+
# # => {"person"=>{"0"=>{"email"=>"none@test.com"}, "1"=>{"phone"=>"555-6789"}}}
|
|
642
668
|
def permit(*filters)
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
filters.flatten.each do |filter|
|
|
646
|
-
case filter
|
|
647
|
-
when Symbol, String
|
|
648
|
-
permitted_scalar_filter(params, filter)
|
|
649
|
-
when Hash
|
|
650
|
-
hash_filter(params, filter)
|
|
651
|
-
end
|
|
652
|
-
end
|
|
669
|
+
permit_filters(filters, on_unpermitted: self.class.action_on_unpermitted_parameters, explicit_arrays: false)
|
|
670
|
+
end
|
|
653
671
|
|
|
654
|
-
|
|
672
|
+
# `expect` is the preferred way to require and permit parameters.
|
|
673
|
+
# It is safer than the previous recommendation to call `permit` and `require`
|
|
674
|
+
# in sequence, which could allow user triggered 500 errors.
|
|
675
|
+
#
|
|
676
|
+
# `expect` is more strict with types to avoid a number of potential pitfalls
|
|
677
|
+
# that may be encountered with the `.require.permit` pattern.
|
|
678
|
+
#
|
|
679
|
+
# For example:
|
|
680
|
+
#
|
|
681
|
+
# params = ActionController::Parameters.new(comment: { text: "hello" })
|
|
682
|
+
# params.expect(comment: [:text])
|
|
683
|
+
# # => #<ActionController::Parameters { text: "hello" } permitted: true>
|
|
684
|
+
#
|
|
685
|
+
# params = ActionController::Parameters.new(comment: [{ text: "hello" }, { text: "world" }])
|
|
686
|
+
# params.expect(comment: [:text])
|
|
687
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: comment
|
|
688
|
+
#
|
|
689
|
+
# In order to permit an array of parameters, the array must be defined
|
|
690
|
+
# explicitly. Use double array brackets, an array inside an array, to
|
|
691
|
+
# declare that an array of parameters is expected.
|
|
692
|
+
#
|
|
693
|
+
# params = ActionController::Parameters.new(comments: [{ text: "hello" }, { text: "world" }])
|
|
694
|
+
# params.expect(comments: [[:text]])
|
|
695
|
+
# # => [#<ActionController::Parameters { "text" => "hello" } permitted: true>,
|
|
696
|
+
# # #<ActionController::Parameters { "text" => "world" } permitted: true>]
|
|
697
|
+
#
|
|
698
|
+
# params = ActionController::Parameters.new(comments: { text: "hello" })
|
|
699
|
+
# params.expect(comments: [[:text]])
|
|
700
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: comments
|
|
701
|
+
#
|
|
702
|
+
# `expect` is intended to protect against array tampering.
|
|
703
|
+
#
|
|
704
|
+
# params = ActionController::Parameters.new(user: "hack")
|
|
705
|
+
# # The previous way of requiring and permitting parameters will error
|
|
706
|
+
# params.require(:user).permit(:name, pets: [:name]) # wrong
|
|
707
|
+
# # => NoMethodError: undefined method `permit' for an instance of String
|
|
708
|
+
#
|
|
709
|
+
# # similarly with nested parameters
|
|
710
|
+
# params = ActionController::Parameters.new(user: { name: "Martin", pets: { name: "hack" } })
|
|
711
|
+
# user_params = params.require(:user).permit(:name, pets: [:name]) # wrong
|
|
712
|
+
# # user_params[:pets] is expected to be an array but is a hash
|
|
713
|
+
#
|
|
714
|
+
# `expect` solves this by being more strict with types.
|
|
715
|
+
#
|
|
716
|
+
# params = ActionController::Parameters.new(user: "hack")
|
|
717
|
+
# params.expect(user: [ :name, pets: [[:name]] ])
|
|
718
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: user
|
|
719
|
+
#
|
|
720
|
+
# # with nested parameters
|
|
721
|
+
# params = ActionController::Parameters.new(user: { name: "Martin", pets: { name: "hack" } })
|
|
722
|
+
# user_params = params.expect(user: [:name, pets: [[:name]] ])
|
|
723
|
+
# user_params[:pets] # => nil
|
|
724
|
+
#
|
|
725
|
+
# As the examples show, `expect` requires the `:user` key, and any root keys
|
|
726
|
+
# similar to the `.require.permit` pattern. If multiple root keys are
|
|
727
|
+
# expected, they will all be required.
|
|
728
|
+
#
|
|
729
|
+
# params = ActionController::Parameters.new(name: "Martin", pies: [{ type: "dessert", flavor: "pumpkin"}])
|
|
730
|
+
# name, pies = params.expect(:name, pies: [[:type, :flavor]])
|
|
731
|
+
# name # => "Martin"
|
|
732
|
+
# pies # => [#<ActionController::Parameters {"type"=>"dessert", "flavor"=>"pumpkin"} permitted: true>]
|
|
733
|
+
#
|
|
734
|
+
# When called with a hash with multiple keys, `expect` will permit the
|
|
735
|
+
# parameters and require the keys in the order they are given in the hash,
|
|
736
|
+
# returning an array of the permitted parameters.
|
|
737
|
+
#
|
|
738
|
+
# params = ActionController::Parameters.new(subject: { name: "Martin" }, object: { pie: "pumpkin" })
|
|
739
|
+
# subject, object = params.expect(subject: [:name], object: [:pie])
|
|
740
|
+
# subject # => #<ActionController::Parameters {"name"=>"Martin"} permitted: true>
|
|
741
|
+
# object # => #<ActionController::Parameters {"pie"=>"pumpkin"} permitted: true>
|
|
742
|
+
#
|
|
743
|
+
# Besides being more strict about array vs hash params, `expect` uses permit
|
|
744
|
+
# internally, so it will behave similarly.
|
|
745
|
+
#
|
|
746
|
+
# params = ActionController::Parameters.new({
|
|
747
|
+
# person: {
|
|
748
|
+
# name: "Francesco",
|
|
749
|
+
# age: 22,
|
|
750
|
+
# pets: [{
|
|
751
|
+
# name: "Purplish",
|
|
752
|
+
# category: "dogs"
|
|
753
|
+
# }]
|
|
754
|
+
# }
|
|
755
|
+
# })
|
|
756
|
+
#
|
|
757
|
+
# permitted = params.expect(person: [ :name, { pets: [[:name]] } ])
|
|
758
|
+
# permitted.permitted? # => true
|
|
759
|
+
# permitted[:name] # => "Francesco"
|
|
760
|
+
# permitted[:age] # => nil
|
|
761
|
+
# permitted[:pets][0][:name] # => "Purplish"
|
|
762
|
+
# permitted[:pets][0][:category] # => nil
|
|
763
|
+
#
|
|
764
|
+
# An array of permitted scalars may be expected with the following:
|
|
765
|
+
#
|
|
766
|
+
# params = ActionController::Parameters.new(tags: ["rails", "parameters"])
|
|
767
|
+
# permitted = params.expect(tags: [])
|
|
768
|
+
# permitted # => ["rails", "parameters"]
|
|
769
|
+
# permitted.is_a?(Array) # => true
|
|
770
|
+
# permitted.size # => 2
|
|
771
|
+
#
|
|
772
|
+
def expect(*filters)
|
|
773
|
+
params = permit_filters(filters)
|
|
774
|
+
keys = filters.flatten.flat_map { |f| f.is_a?(Hash) ? f.keys : f }
|
|
775
|
+
values = params.require(keys)
|
|
776
|
+
values.size == 1 ? values.first : values
|
|
777
|
+
end
|
|
655
778
|
|
|
656
|
-
|
|
779
|
+
# Same as `expect`, but raises an `ActionController::ExpectedParameterMissing`
|
|
780
|
+
# instead of `ActionController::ParameterMissing`. Unlike `expect` which
|
|
781
|
+
# will render a 400 response, `expect!` will raise an exception that is
|
|
782
|
+
# not handled. This is intended for debugging invalid params for an
|
|
783
|
+
# internal API where incorrectly formatted params would indicate a bug
|
|
784
|
+
# in a client library that should be fixed.
|
|
785
|
+
#
|
|
786
|
+
def expect!(*filters)
|
|
787
|
+
expect(*filters)
|
|
788
|
+
rescue ParameterMissing => e
|
|
789
|
+
raise ExpectedParameterMissing.new(e.param, e.keys)
|
|
657
790
|
end
|
|
658
791
|
|
|
659
|
-
# Returns a parameter for the given
|
|
660
|
-
# returns +nil+.
|
|
792
|
+
# Returns a parameter for the given `key`. If not found, returns `nil`.
|
|
661
793
|
#
|
|
662
|
-
#
|
|
663
|
-
#
|
|
664
|
-
#
|
|
794
|
+
# params = ActionController::Parameters.new(person: { name: "Francesco" })
|
|
795
|
+
# params[:person] # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
|
796
|
+
# params[:none] # => nil
|
|
665
797
|
def [](key)
|
|
666
798
|
convert_hashes_to_parameters(key, @parameters[key])
|
|
667
799
|
end
|
|
668
800
|
|
|
669
|
-
# Assigns a value to a given
|
|
801
|
+
# Assigns a value to a given `key`. The given key may still get filtered out
|
|
670
802
|
# when #permit is called.
|
|
671
803
|
def []=(key, value)
|
|
672
804
|
@parameters[key] = value
|
|
673
805
|
end
|
|
674
806
|
|
|
675
|
-
# Returns a parameter for the given
|
|
676
|
-
#
|
|
677
|
-
#
|
|
678
|
-
#
|
|
679
|
-
#
|
|
680
|
-
#
|
|
681
|
-
#
|
|
682
|
-
#
|
|
683
|
-
#
|
|
684
|
-
#
|
|
685
|
-
#
|
|
686
|
-
#
|
|
687
|
-
#
|
|
807
|
+
# Returns a parameter for the given `key`. If the `key` can't be found, there
|
|
808
|
+
# are several options: With no other arguments, it will raise an
|
|
809
|
+
# ActionController::ParameterMissing error; if a second argument is given, then
|
|
810
|
+
# that is returned (converted to an instance of `ActionController::Parameters`
|
|
811
|
+
# if possible); if a block is given, then that will be run and its result
|
|
812
|
+
# returned.
|
|
813
|
+
#
|
|
814
|
+
# params = ActionController::Parameters.new(person: { name: "Francesco" })
|
|
815
|
+
# params.fetch(:person) # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
|
816
|
+
# params.fetch(:none) # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: none
|
|
817
|
+
# params.fetch(:none, {}) # => #<ActionController::Parameters {} permitted: false>
|
|
818
|
+
# params.fetch(:none, "Francesco") # => "Francesco"
|
|
819
|
+
# params.fetch(:none) { "Francesco" } # => "Francesco"
|
|
688
820
|
def fetch(key, *args)
|
|
689
821
|
convert_value_to_parameters(
|
|
690
822
|
@parameters.fetch(key) {
|
|
@@ -697,44 +829,43 @@ module ActionController
|
|
|
697
829
|
)
|
|
698
830
|
end
|
|
699
831
|
|
|
700
|
-
# Extracts the nested parameter from the given
|
|
701
|
-
#
|
|
832
|
+
# Extracts the nested parameter from the given `keys` by calling `dig` at each
|
|
833
|
+
# step. Returns `nil` if any intermediate step is `nil`.
|
|
702
834
|
#
|
|
703
|
-
#
|
|
704
|
-
#
|
|
705
|
-
#
|
|
835
|
+
# params = ActionController::Parameters.new(foo: { bar: { baz: 1 } })
|
|
836
|
+
# params.dig(:foo, :bar, :baz) # => 1
|
|
837
|
+
# params.dig(:foo, :zot, :xyz) # => nil
|
|
706
838
|
#
|
|
707
|
-
#
|
|
708
|
-
#
|
|
839
|
+
# params2 = ActionController::Parameters.new(foo: [10, 11, 12])
|
|
840
|
+
# params2.dig(:foo, 1) # => 11
|
|
709
841
|
def dig(*keys)
|
|
710
842
|
convert_hashes_to_parameters(keys.first, @parameters[keys.first])
|
|
711
843
|
@parameters.dig(*keys)
|
|
712
844
|
end
|
|
713
845
|
|
|
714
|
-
# Returns a new
|
|
715
|
-
#
|
|
716
|
-
# don't exist, returns an empty hash.
|
|
846
|
+
# Returns a new `ActionController::Parameters` instance that includes only the
|
|
847
|
+
# given `keys`. If the given `keys` don't exist, returns an empty hash.
|
|
717
848
|
#
|
|
718
|
-
#
|
|
719
|
-
#
|
|
720
|
-
#
|
|
849
|
+
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
|
850
|
+
# params.slice(:a, :b) # => #<ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
|
|
851
|
+
# params.slice(:d) # => #<ActionController::Parameters {} permitted: false>
|
|
721
852
|
def slice(*keys)
|
|
722
853
|
new_instance_with_inherited_permitted_status(@parameters.slice(*keys))
|
|
723
854
|
end
|
|
724
855
|
|
|
725
|
-
# Returns the current
|
|
726
|
-
#
|
|
856
|
+
# Returns the current `ActionController::Parameters` instance which contains
|
|
857
|
+
# only the given `keys`.
|
|
727
858
|
def slice!(*keys)
|
|
728
859
|
@parameters.slice!(*keys)
|
|
729
860
|
self
|
|
730
861
|
end
|
|
731
862
|
|
|
732
|
-
# Returns a new
|
|
733
|
-
#
|
|
863
|
+
# Returns a new `ActionController::Parameters` instance that filters out the
|
|
864
|
+
# given `keys`.
|
|
734
865
|
#
|
|
735
|
-
#
|
|
736
|
-
#
|
|
737
|
-
#
|
|
866
|
+
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
|
867
|
+
# params.except(:a, :b) # => #<ActionController::Parameters {"c"=>3} permitted: false>
|
|
868
|
+
# params.except(:d) # => #<ActionController::Parameters {"a"=>1, "b"=>2, "c"=>3} permitted: false>
|
|
738
869
|
def except(*keys)
|
|
739
870
|
new_instance_with_inherited_permitted_status(@parameters.except(*keys))
|
|
740
871
|
end
|
|
@@ -742,19 +873,19 @@ module ActionController
|
|
|
742
873
|
|
|
743
874
|
# Removes and returns the key/value pairs matching the given keys.
|
|
744
875
|
#
|
|
745
|
-
#
|
|
746
|
-
#
|
|
747
|
-
#
|
|
876
|
+
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
|
877
|
+
# params.extract!(:a, :b) # => #<ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
|
|
878
|
+
# params # => #<ActionController::Parameters {"c"=>3} permitted: false>
|
|
748
879
|
def extract!(*keys)
|
|
749
880
|
new_instance_with_inherited_permitted_status(@parameters.extract!(*keys))
|
|
750
881
|
end
|
|
751
882
|
|
|
752
|
-
# Returns a new
|
|
753
|
-
# running
|
|
883
|
+
# Returns a new `ActionController::Parameters` instance with the results of
|
|
884
|
+
# running `block` once for every value. The keys are unchanged.
|
|
754
885
|
#
|
|
755
|
-
#
|
|
756
|
-
#
|
|
757
|
-
#
|
|
886
|
+
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
|
887
|
+
# params.transform_values { |x| x * 2 }
|
|
888
|
+
# # => #<ActionController::Parameters {"a"=>2, "b"=>4, "c"=>6} permitted: false>
|
|
758
889
|
def transform_values
|
|
759
890
|
return to_enum(:transform_values) unless block_given?
|
|
760
891
|
new_instance_with_inherited_permitted_status(
|
|
@@ -763,15 +894,15 @@ module ActionController
|
|
|
763
894
|
end
|
|
764
895
|
|
|
765
896
|
# Performs values transformation and returns the altered
|
|
766
|
-
#
|
|
897
|
+
# `ActionController::Parameters` instance.
|
|
767
898
|
def transform_values!
|
|
768
899
|
return to_enum(:transform_values!) unless block_given?
|
|
769
900
|
@parameters.transform_values! { |v| yield convert_value_to_parameters(v) }
|
|
770
901
|
self
|
|
771
902
|
end
|
|
772
903
|
|
|
773
|
-
# Returns a new
|
|
774
|
-
#
|
|
904
|
+
# Returns a new `ActionController::Parameters` instance with the results of
|
|
905
|
+
# running `block` once for every key. The values are unchanged.
|
|
775
906
|
def transform_keys(&block)
|
|
776
907
|
return to_enum(:transform_keys) unless block_given?
|
|
777
908
|
new_instance_with_inherited_permitted_status(
|
|
@@ -780,53 +911,53 @@ module ActionController
|
|
|
780
911
|
end
|
|
781
912
|
|
|
782
913
|
# Performs keys transformation and returns the altered
|
|
783
|
-
#
|
|
914
|
+
# `ActionController::Parameters` instance.
|
|
784
915
|
def transform_keys!(&block)
|
|
785
916
|
return to_enum(:transform_keys!) unless block_given?
|
|
786
917
|
@parameters.transform_keys!(&block)
|
|
787
918
|
self
|
|
788
919
|
end
|
|
789
920
|
|
|
790
|
-
# Returns a new
|
|
791
|
-
#
|
|
792
|
-
#
|
|
921
|
+
# Returns a new `ActionController::Parameters` instance with the results of
|
|
922
|
+
# running `block` once for every key. This includes the keys from the root hash
|
|
923
|
+
# and from all nested hashes and arrays. The values are unchanged.
|
|
793
924
|
def deep_transform_keys(&block)
|
|
794
925
|
new_instance_with_inherited_permitted_status(
|
|
795
926
|
_deep_transform_keys_in_object(@parameters, &block).to_unsafe_h
|
|
796
927
|
)
|
|
797
928
|
end
|
|
798
929
|
|
|
799
|
-
# Returns the same
|
|
800
|
-
#
|
|
801
|
-
#
|
|
930
|
+
# Returns the same `ActionController::Parameters` instance with changed keys.
|
|
931
|
+
# This includes the keys from the root hash and from all nested hashes and
|
|
932
|
+
# arrays. The values are unchanged.
|
|
802
933
|
def deep_transform_keys!(&block)
|
|
803
934
|
@parameters = _deep_transform_keys_in_object(@parameters, &block).to_unsafe_h
|
|
804
935
|
self
|
|
805
936
|
end
|
|
806
937
|
|
|
807
|
-
# Deletes a key-value pair from
|
|
808
|
-
#
|
|
809
|
-
#
|
|
810
|
-
#
|
|
938
|
+
# Deletes a key-value pair from `Parameters` and returns the value. If `key` is
|
|
939
|
+
# not found, returns `nil` (or, with optional code block, yields `key` and
|
|
940
|
+
# returns the result). This method is similar to #extract!, which returns the
|
|
941
|
+
# corresponding `ActionController::Parameters` object.
|
|
811
942
|
def delete(key, &block)
|
|
812
943
|
convert_value_to_parameters(@parameters.delete(key, &block))
|
|
813
944
|
end
|
|
814
945
|
|
|
815
|
-
# Returns a new
|
|
816
|
-
#
|
|
946
|
+
# Returns a new `ActionController::Parameters` instance with only items that the
|
|
947
|
+
# block evaluates to true.
|
|
817
948
|
def select(&block)
|
|
818
949
|
new_instance_with_inherited_permitted_status(@parameters.select(&block))
|
|
819
950
|
end
|
|
820
951
|
|
|
821
|
-
# Equivalent to Hash#keep_if, but returns
|
|
952
|
+
# Equivalent to Hash#keep_if, but returns `nil` if no changes were made.
|
|
822
953
|
def select!(&block)
|
|
823
954
|
@parameters.select!(&block)
|
|
824
955
|
self
|
|
825
956
|
end
|
|
826
957
|
alias_method :keep_if, :select!
|
|
827
958
|
|
|
828
|
-
# Returns a new
|
|
829
|
-
#
|
|
959
|
+
# Returns a new `ActionController::Parameters` instance with items that the
|
|
960
|
+
# block evaluates to true removed.
|
|
830
961
|
def reject(&block)
|
|
831
962
|
new_instance_with_inherited_permitted_status(@parameters.reject(&block))
|
|
832
963
|
end
|
|
@@ -838,24 +969,26 @@ module ActionController
|
|
|
838
969
|
end
|
|
839
970
|
alias_method :delete_if, :reject!
|
|
840
971
|
|
|
841
|
-
# Returns a new
|
|
972
|
+
# Returns a new `ActionController::Parameters` instance with `nil` values
|
|
973
|
+
# removed.
|
|
842
974
|
def compact
|
|
843
975
|
new_instance_with_inherited_permitted_status(@parameters.compact)
|
|
844
976
|
end
|
|
845
977
|
|
|
846
|
-
# Removes all
|
|
978
|
+
# Removes all `nil` values in place and returns `self`, or `nil` if no changes
|
|
979
|
+
# were made.
|
|
847
980
|
def compact!
|
|
848
981
|
self if @parameters.compact!
|
|
849
982
|
end
|
|
850
983
|
|
|
851
|
-
# Returns a new
|
|
852
|
-
# Uses Object#blank? for determining if a value is blank.
|
|
984
|
+
# Returns a new `ActionController::Parameters` instance without the blank
|
|
985
|
+
# values. Uses Object#blank? for determining if a value is blank.
|
|
853
986
|
def compact_blank
|
|
854
987
|
reject { |_k, v| v.blank? }
|
|
855
988
|
end
|
|
856
989
|
|
|
857
|
-
# Removes all blank values in place and returns self.
|
|
858
|
-
#
|
|
990
|
+
# Removes all blank values in place and returns self. Uses Object#blank? for
|
|
991
|
+
# determining if a value is blank.
|
|
859
992
|
def compact_blank!
|
|
860
993
|
reject! { |_k, v| v.blank? }
|
|
861
994
|
end
|
|
@@ -867,14 +1000,14 @@ module ActionController
|
|
|
867
1000
|
|
|
868
1001
|
alias value? has_value?
|
|
869
1002
|
|
|
870
|
-
# Returns values that were assigned to the given
|
|
871
|
-
#
|
|
1003
|
+
# Returns values that were assigned to the given `keys`. Note that all the
|
|
1004
|
+
# `Hash` objects will be converted to `ActionController::Parameters`.
|
|
872
1005
|
def values_at(*keys)
|
|
873
1006
|
convert_value_to_parameters(@parameters.values_at(*keys))
|
|
874
1007
|
end
|
|
875
1008
|
|
|
876
|
-
# Returns a new
|
|
877
|
-
#
|
|
1009
|
+
# Returns a new `ActionController::Parameters` instance with all keys from
|
|
1010
|
+
# `other_hash` merged into current hash.
|
|
878
1011
|
def merge(other_hash)
|
|
879
1012
|
new_instance_with_inherited_permitted_status(
|
|
880
1013
|
@parameters.merge(other_hash.to_h)
|
|
@@ -884,8 +1017,8 @@ module ActionController
|
|
|
884
1017
|
##
|
|
885
1018
|
# :call-seq: merge!(other_hash)
|
|
886
1019
|
#
|
|
887
|
-
# Returns the current
|
|
888
|
-
#
|
|
1020
|
+
# Returns the current `ActionController::Parameters` instance with `other_hash`
|
|
1021
|
+
# merged into current hash.
|
|
889
1022
|
def merge!(other_hash, &block)
|
|
890
1023
|
@parameters.merge!(other_hash.to_h, &block)
|
|
891
1024
|
self
|
|
@@ -895,8 +1028,8 @@ module ActionController
|
|
|
895
1028
|
other_hash.is_a?(ActiveSupport::DeepMergeable)
|
|
896
1029
|
end
|
|
897
1030
|
|
|
898
|
-
# Returns a new
|
|
899
|
-
#
|
|
1031
|
+
# Returns a new `ActionController::Parameters` instance with all keys from
|
|
1032
|
+
# current hash merged into `other_hash`.
|
|
900
1033
|
def reverse_merge(other_hash)
|
|
901
1034
|
new_instance_with_inherited_permitted_status(
|
|
902
1035
|
other_hash.to_h.merge(@parameters)
|
|
@@ -904,17 +1037,17 @@ module ActionController
|
|
|
904
1037
|
end
|
|
905
1038
|
alias_method :with_defaults, :reverse_merge
|
|
906
1039
|
|
|
907
|
-
# Returns the current
|
|
908
|
-
#
|
|
1040
|
+
# Returns the current `ActionController::Parameters` instance with current hash
|
|
1041
|
+
# merged into `other_hash`.
|
|
909
1042
|
def reverse_merge!(other_hash)
|
|
910
1043
|
@parameters.merge!(other_hash.to_h) { |key, left, right| left }
|
|
911
1044
|
self
|
|
912
1045
|
end
|
|
913
1046
|
alias_method :with_defaults!, :reverse_merge!
|
|
914
1047
|
|
|
915
|
-
# This is required by ActiveModel attribute assignment, so that user can
|
|
916
|
-
#
|
|
917
|
-
#
|
|
1048
|
+
# This is required by ActiveModel attribute assignment, so that user can pass
|
|
1049
|
+
# `Parameters` to a mass assignment methods in a model. It should not matter as
|
|
1050
|
+
# we are using `HashWithIndifferentAccess` internally.
|
|
918
1051
|
def stringify_keys # :nodoc:
|
|
919
1052
|
dup
|
|
920
1053
|
end
|
|
@@ -939,13 +1072,13 @@ module ActionController
|
|
|
939
1072
|
@parameters = coder.map.with_indifferent_access
|
|
940
1073
|
@permitted = false
|
|
941
1074
|
when "!ruby/hash-with-ivars:ActionController::Parameters"
|
|
942
|
-
# YAML 2.0.9's Hash subclass format where keys and values
|
|
943
|
-
#
|
|
1075
|
+
# YAML 2.0.9's Hash subclass format where keys and values were stored under an
|
|
1076
|
+
# elements hash and `permitted` within an ivars hash.
|
|
944
1077
|
@parameters = coder.map["elements"].with_indifferent_access
|
|
945
1078
|
@permitted = coder.map["ivars"][:@permitted]
|
|
946
1079
|
when "!ruby/object:ActionController::Parameters"
|
|
947
|
-
# YAML's Object format. Only needed because of the format
|
|
948
|
-
#
|
|
1080
|
+
# YAML's Object format. Only needed because of the format backwards
|
|
1081
|
+
# compatibility above, otherwise equivalent to YAML's initialization.
|
|
949
1082
|
@parameters, @permitted = coder.map["parameters"], coder.map["permitted"]
|
|
950
1083
|
end
|
|
951
1084
|
end
|
|
@@ -954,25 +1087,26 @@ module ActionController
|
|
|
954
1087
|
coder.map = { "parameters" => @parameters, "permitted" => @permitted }
|
|
955
1088
|
end
|
|
956
1089
|
|
|
957
|
-
# Returns a duplicate
|
|
1090
|
+
# Returns a duplicate `ActionController::Parameters` instance with the same
|
|
1091
|
+
# permitted parameters.
|
|
958
1092
|
def deep_dup
|
|
959
1093
|
self.class.new(@parameters.deep_dup, @logging_context).tap do |duplicate|
|
|
960
1094
|
duplicate.permitted = @permitted
|
|
961
1095
|
end
|
|
962
1096
|
end
|
|
963
1097
|
|
|
964
|
-
# Returns parameter value for the given
|
|
1098
|
+
# Returns parameter value for the given `key` separated by `delimiter`.
|
|
965
1099
|
#
|
|
966
|
-
#
|
|
967
|
-
#
|
|
968
|
-
#
|
|
969
|
-
#
|
|
1100
|
+
# params = ActionController::Parameters.new(id: "1_123", tags: "ruby,rails")
|
|
1101
|
+
# params.extract_value(:id) # => ["1", "123"]
|
|
1102
|
+
# params.extract_value(:tags, delimiter: ",") # => ["ruby", "rails"]
|
|
1103
|
+
# params.extract_value(:non_existent_key) # => nil
|
|
970
1104
|
#
|
|
971
|
-
# Note that if the given
|
|
972
|
-
#
|
|
1105
|
+
# Note that if the given `key`'s value contains blank elements, then the
|
|
1106
|
+
# returned array will include empty strings.
|
|
973
1107
|
#
|
|
974
|
-
#
|
|
975
|
-
#
|
|
1108
|
+
# params = ActionController::Parameters.new(tags: "ruby,rails,,web")
|
|
1109
|
+
# params.extract_value(:tags, delimiter: ",") # => ["ruby", "rails", "", "web"]
|
|
976
1110
|
def extract_value(key, delimiter: "_")
|
|
977
1111
|
@parameters[key]&.split(delimiter, -1)
|
|
978
1112
|
end
|
|
@@ -992,6 +1126,26 @@ module ActionController
|
|
|
992
1126
|
hash
|
|
993
1127
|
end
|
|
994
1128
|
|
|
1129
|
+
# Filters self and optionally checks for unpermitted keys
|
|
1130
|
+
def permit_filters(filters, on_unpermitted: nil, explicit_arrays: true)
|
|
1131
|
+
params = self.class.new
|
|
1132
|
+
|
|
1133
|
+
filters.flatten.each do |filter|
|
|
1134
|
+
case filter
|
|
1135
|
+
when Symbol, String
|
|
1136
|
+
# Declaration [:name, "age"]
|
|
1137
|
+
permitted_scalar_filter(params, filter)
|
|
1138
|
+
when Hash
|
|
1139
|
+
# Declaration [{ person: ... }]
|
|
1140
|
+
hash_filter(params, filter, on_unpermitted:, explicit_arrays:)
|
|
1141
|
+
end
|
|
1142
|
+
end
|
|
1143
|
+
|
|
1144
|
+
unpermitted_parameters!(params, on_unpermitted:)
|
|
1145
|
+
|
|
1146
|
+
params.permit!
|
|
1147
|
+
end
|
|
1148
|
+
|
|
995
1149
|
private
|
|
996
1150
|
def new_instance_with_inherited_permitted_status(hash)
|
|
997
1151
|
self.class.new(hash, @logging_context).tap do |new_instance|
|
|
@@ -1081,23 +1235,45 @@ module ActionController
|
|
|
1081
1235
|
end
|
|
1082
1236
|
end
|
|
1083
1237
|
|
|
1084
|
-
|
|
1238
|
+
# When an array is expected, you must specify an array explicitly
|
|
1239
|
+
# using the following format:
|
|
1240
|
+
#
|
|
1241
|
+
# params.expect(comments: [[:flavor]])
|
|
1242
|
+
#
|
|
1243
|
+
# Which will match only the following array formats:
|
|
1244
|
+
#
|
|
1245
|
+
# { pies: [{ flavor: "rhubarb" }, { flavor: "apple" }] }
|
|
1246
|
+
# { pies: { "0" => { flavor: "key lime" }, "1" => { flavor: "mince" } } }
|
|
1247
|
+
#
|
|
1248
|
+
# When using `permit`, arrays are specified the same way as hashes:
|
|
1249
|
+
#
|
|
1250
|
+
# params.expect(pies: [:flavor])
|
|
1251
|
+
#
|
|
1252
|
+
# In this case, `permit` would also allow matching with a hash (or vice versa):
|
|
1253
|
+
#
|
|
1254
|
+
# { pies: { flavor: "cherry" } }
|
|
1255
|
+
#
|
|
1256
|
+
def array_filter?(filter)
|
|
1257
|
+
filter.is_a?(Array) && filter.size == 1 && filter.first.is_a?(Array)
|
|
1258
|
+
end
|
|
1259
|
+
|
|
1260
|
+
# Called when an explicit array filter is encountered.
|
|
1261
|
+
def each_array_element(object, filter, &block)
|
|
1085
1262
|
case object
|
|
1086
1263
|
when Array
|
|
1087
1264
|
object.grep(Parameters).filter_map(&block)
|
|
1088
1265
|
when Parameters
|
|
1089
1266
|
if object.nested_attributes? && !specify_numeric_keys?(filter)
|
|
1090
1267
|
object.each_nested_attribute(&block)
|
|
1091
|
-
else
|
|
1092
|
-
yield object
|
|
1093
1268
|
end
|
|
1094
1269
|
end
|
|
1095
1270
|
end
|
|
1096
1271
|
|
|
1097
|
-
def unpermitted_parameters!(params)
|
|
1272
|
+
def unpermitted_parameters!(params, on_unpermitted: self.class.action_on_unpermitted_parameters)
|
|
1273
|
+
return unless on_unpermitted
|
|
1098
1274
|
unpermitted_keys = unpermitted_keys(params)
|
|
1099
1275
|
if unpermitted_keys.any?
|
|
1100
|
-
case
|
|
1276
|
+
case on_unpermitted
|
|
1101
1277
|
when :log
|
|
1102
1278
|
name = "unpermitted_parameters.action_controller"
|
|
1103
1279
|
ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys, context: @logging_context)
|
|
@@ -1111,18 +1287,14 @@ module ActionController
|
|
|
1111
1287
|
keys - params.keys - always_permitted_parameters
|
|
1112
1288
|
end
|
|
1113
1289
|
|
|
1290
|
+
# This is a list of permitted scalar types that includes the ones supported in
|
|
1291
|
+
# XML and JSON requests.
|
|
1114
1292
|
#
|
|
1115
|
-
#
|
|
1116
|
-
#
|
|
1117
|
-
|
|
1118
|
-
# This is a list of permitted scalar types that includes the ones
|
|
1119
|
-
# supported in XML and JSON requests.
|
|
1120
|
-
#
|
|
1121
|
-
# This list is in particular used to filter ordinary requests, \String goes
|
|
1122
|
-
# as first element to quickly short-circuit the common case.
|
|
1293
|
+
# This list is in particular used to filter ordinary requests, String goes as
|
|
1294
|
+
# first element to quickly short-circuit the common case.
|
|
1123
1295
|
#
|
|
1124
|
-
# If you modify this collection please update the one in the #permit doc
|
|
1125
|
-
#
|
|
1296
|
+
# If you modify this collection please update the one in the #permit doc as
|
|
1297
|
+
# well.
|
|
1126
1298
|
PERMITTED_SCALAR_TYPES = [
|
|
1127
1299
|
String,
|
|
1128
1300
|
Symbol,
|
|
@@ -1147,12 +1319,12 @@ module ActionController
|
|
|
1147
1319
|
#
|
|
1148
1320
|
# For example:
|
|
1149
1321
|
#
|
|
1150
|
-
#
|
|
1151
|
-
#
|
|
1322
|
+
# puts self.keys #=> ["zipcode(90210i)"]
|
|
1323
|
+
# params = {}
|
|
1152
1324
|
#
|
|
1153
|
-
#
|
|
1325
|
+
# permitted_scalar_filter(params, "zipcode")
|
|
1154
1326
|
#
|
|
1155
|
-
#
|
|
1327
|
+
# puts params.keys # => ["zipcode"]
|
|
1156
1328
|
def permitted_scalar_filter(params, permitted_key)
|
|
1157
1329
|
permitted_key = permitted_key.to_s
|
|
1158
1330
|
|
|
@@ -1168,45 +1340,63 @@ module ActionController
|
|
|
1168
1340
|
end
|
|
1169
1341
|
end
|
|
1170
1342
|
|
|
1171
|
-
def array_of_permitted_scalars?(value)
|
|
1172
|
-
if value.is_a?(Array) && value.all? { |element| permitted_scalar?(element) }
|
|
1173
|
-
yield value
|
|
1174
|
-
end
|
|
1175
|
-
end
|
|
1176
|
-
|
|
1177
1343
|
def non_scalar?(value)
|
|
1178
1344
|
value.is_a?(Array) || value.is_a?(Parameters)
|
|
1179
1345
|
end
|
|
1180
1346
|
|
|
1181
1347
|
EMPTY_ARRAY = [] # :nodoc:
|
|
1182
1348
|
EMPTY_HASH = {} # :nodoc:
|
|
1183
|
-
def hash_filter(params, filter)
|
|
1349
|
+
def hash_filter(params, filter, on_unpermitted: self.class.action_on_unpermitted_parameters, explicit_arrays: false)
|
|
1184
1350
|
filter = filter.with_indifferent_access
|
|
1185
1351
|
|
|
1186
1352
|
# Slicing filters out non-declared keys.
|
|
1187
1353
|
slice(*filter.keys).each do |key, value|
|
|
1188
1354
|
next unless value
|
|
1189
1355
|
next unless has_key? key
|
|
1356
|
+
result = permit_value(value, filter[key], on_unpermitted:, explicit_arrays:)
|
|
1357
|
+
params[key] = result unless result.nil?
|
|
1358
|
+
end
|
|
1359
|
+
end
|
|
1190
1360
|
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1361
|
+
def permit_value(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1362
|
+
if filter == EMPTY_ARRAY # Declaration { comment_ids: [] }.
|
|
1363
|
+
permit_array_of_scalars(value)
|
|
1364
|
+
elsif filter == EMPTY_HASH # Declaration { preferences: {} }.
|
|
1365
|
+
permit_hash(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1366
|
+
elsif array_filter?(filter) # Declaration { comments: [[:text]] }
|
|
1367
|
+
permit_array_of_hashes(value, filter.first, on_unpermitted:, explicit_arrays:)
|
|
1368
|
+
elsif explicit_arrays # Declaration { user: { address: ... } } or { user: [:name, ...] } (only allows hash value)
|
|
1369
|
+
permit_hash(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1370
|
+
elsif non_scalar?(value) # Declaration { user: { address: ... } } or { user: [:name, ...] }
|
|
1371
|
+
permit_hash_or_array(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1372
|
+
end
|
|
1373
|
+
end
|
|
1374
|
+
|
|
1375
|
+
def permit_array_of_scalars(value)
|
|
1376
|
+
value if value.is_a?(Array) && value.all? { |element| permitted_scalar?(element) }
|
|
1377
|
+
end
|
|
1378
|
+
|
|
1379
|
+
def permit_array_of_hashes(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1380
|
+
each_array_element(value, filter) do |element|
|
|
1381
|
+
element.permit_filters(Array.wrap(filter), on_unpermitted:, explicit_arrays:)
|
|
1382
|
+
end
|
|
1383
|
+
end
|
|
1384
|
+
|
|
1385
|
+
def permit_hash(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1386
|
+
return unless value.is_a?(Parameters)
|
|
1387
|
+
|
|
1388
|
+
if filter == EMPTY_HASH
|
|
1389
|
+
permit_any_in_parameters(value)
|
|
1390
|
+
else
|
|
1391
|
+
value.permit_filters(Array.wrap(filter), on_unpermitted:, explicit_arrays:)
|
|
1207
1392
|
end
|
|
1208
1393
|
end
|
|
1209
1394
|
|
|
1395
|
+
def permit_hash_or_array(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1396
|
+
permit_array_of_hashes(value, filter, on_unpermitted:, explicit_arrays:) ||
|
|
1397
|
+
permit_hash(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1398
|
+
end
|
|
1399
|
+
|
|
1210
1400
|
def permit_any_in_parameters(params)
|
|
1211
1401
|
self.class.new.tap do |sanitized|
|
|
1212
1402
|
params.each do |key, value|
|
|
@@ -1247,77 +1437,77 @@ module ActionController
|
|
|
1247
1437
|
end
|
|
1248
1438
|
end
|
|
1249
1439
|
|
|
1250
|
-
#
|
|
1440
|
+
# # Strong Parameters
|
|
1251
1441
|
#
|
|
1252
|
-
# It provides an interface for protecting attributes from end-user
|
|
1253
|
-
#
|
|
1254
|
-
#
|
|
1255
|
-
# enumerated.
|
|
1442
|
+
# It provides an interface for protecting attributes from end-user assignment.
|
|
1443
|
+
# This makes Action Controller parameters forbidden to be used in Active Model
|
|
1444
|
+
# mass assignment until they have been explicitly enumerated.
|
|
1256
1445
|
#
|
|
1257
1446
|
# In addition, parameters can be marked as required and flow through a
|
|
1258
|
-
# predefined raise/rescue flow to end up as a
|
|
1259
|
-
# effort.
|
|
1447
|
+
# predefined raise/rescue flow to end up as a `400 Bad Request` with no effort.
|
|
1260
1448
|
#
|
|
1261
|
-
#
|
|
1262
|
-
#
|
|
1263
|
-
#
|
|
1264
|
-
#
|
|
1265
|
-
#
|
|
1266
|
-
#
|
|
1267
|
-
#
|
|
1268
|
-
#
|
|
1269
|
-
#
|
|
1270
|
-
# # This will pass with flying colors as long as there's a person key in the
|
|
1271
|
-
# # parameters, otherwise it'll raise an ActionController::ParameterMissing
|
|
1272
|
-
# # exception, which will get caught by ActionController::Base and turned
|
|
1273
|
-
# # into a 400 Bad Request reply.
|
|
1274
|
-
# def update
|
|
1275
|
-
# redirect_to current_account.people.find(params[:id]).tap { |person|
|
|
1276
|
-
# person.update!(person_params)
|
|
1277
|
-
# }
|
|
1278
|
-
# end
|
|
1449
|
+
# class PeopleController < ActionController::Base
|
|
1450
|
+
# # Using "Person.create(params[:person])" would raise an
|
|
1451
|
+
# # ActiveModel::ForbiddenAttributesError exception because it'd
|
|
1452
|
+
# # be using mass assignment without an explicit permit step.
|
|
1453
|
+
# # This is the recommended form:
|
|
1454
|
+
# def create
|
|
1455
|
+
# Person.create(person_params)
|
|
1456
|
+
# end
|
|
1279
1457
|
#
|
|
1280
|
-
#
|
|
1281
|
-
# #
|
|
1282
|
-
# #
|
|
1283
|
-
# #
|
|
1284
|
-
#
|
|
1285
|
-
#
|
|
1286
|
-
#
|
|
1458
|
+
# # This will pass with flying colors as long as there's a person key in the
|
|
1459
|
+
# # parameters, otherwise it'll raise an ActionController::ParameterMissing
|
|
1460
|
+
# # exception, which will get caught by ActionController::Base and turned
|
|
1461
|
+
# # into a 400 Bad Request reply.
|
|
1462
|
+
# def update
|
|
1463
|
+
# redirect_to current_account.people.find(params[:id]).tap { |person|
|
|
1464
|
+
# person.update!(person_params)
|
|
1465
|
+
# }
|
|
1287
1466
|
# end
|
|
1288
|
-
# end
|
|
1289
1467
|
#
|
|
1290
|
-
#
|
|
1291
|
-
#
|
|
1292
|
-
#
|
|
1468
|
+
# private
|
|
1469
|
+
# # Using a private method to encapsulate the permissible parameters is
|
|
1470
|
+
# # a good pattern since you'll be able to reuse the same permit
|
|
1471
|
+
# # list between create and update. Also, you can specialize this method
|
|
1472
|
+
# # with per-user checking of permissible attributes.
|
|
1473
|
+
# def person_params
|
|
1474
|
+
# params.expect(person: [:name, :age])
|
|
1475
|
+
# end
|
|
1476
|
+
# end
|
|
1293
1477
|
#
|
|
1294
|
-
#
|
|
1295
|
-
#
|
|
1296
|
-
#
|
|
1297
|
-
#
|
|
1478
|
+
# In order to use `accepts_nested_attributes_for` with Strong Parameters, you
|
|
1479
|
+
# will need to specify which nested attributes should be permitted. You might
|
|
1480
|
+
# want to allow `:id` and `:_destroy`, see ActiveRecord::NestedAttributes for
|
|
1481
|
+
# more information.
|
|
1298
1482
|
#
|
|
1299
|
-
#
|
|
1300
|
-
#
|
|
1301
|
-
#
|
|
1483
|
+
# class Person
|
|
1484
|
+
# has_many :pets
|
|
1485
|
+
# accepts_nested_attributes_for :pets
|
|
1302
1486
|
# end
|
|
1303
1487
|
#
|
|
1304
|
-
#
|
|
1488
|
+
# class PeopleController < ActionController::Base
|
|
1489
|
+
# def create
|
|
1490
|
+
# Person.create(person_params)
|
|
1491
|
+
# end
|
|
1305
1492
|
#
|
|
1306
|
-
#
|
|
1493
|
+
# ...
|
|
1307
1494
|
#
|
|
1308
|
-
#
|
|
1309
|
-
#
|
|
1310
|
-
#
|
|
1311
|
-
#
|
|
1312
|
-
#
|
|
1313
|
-
#
|
|
1314
|
-
#
|
|
1495
|
+
# private
|
|
1496
|
+
#
|
|
1497
|
+
# def person_params
|
|
1498
|
+
# # It's mandatory to specify the nested attributes that should be permitted.
|
|
1499
|
+
# # If you use `permit` with just the key that points to the nested attributes hash,
|
|
1500
|
+
# # it will return an empty hash.
|
|
1501
|
+
# params.expect(person: [ :name, :age, pets_attributes: [ :id, :name, :category ] ])
|
|
1502
|
+
# end
|
|
1503
|
+
# end
|
|
1315
1504
|
#
|
|
1316
|
-
# See ActionController::Parameters.
|
|
1317
|
-
#
|
|
1505
|
+
# See ActionController::Parameters.expect,
|
|
1506
|
+
# See ActionController::Parameters.require, and
|
|
1507
|
+
# ActionController::Parameters.permit for more information.
|
|
1318
1508
|
module StrongParameters
|
|
1319
|
-
# Returns a new ActionController::Parameters object that
|
|
1320
|
-
#
|
|
1509
|
+
# Returns a new ActionController::Parameters object that has been instantiated
|
|
1510
|
+
# with the `request.parameters`.
|
|
1321
1511
|
def params
|
|
1322
1512
|
@_params ||= begin
|
|
1323
1513
|
context = {
|
|
@@ -1330,9 +1520,9 @@ module ActionController
|
|
|
1330
1520
|
end
|
|
1331
1521
|
end
|
|
1332
1522
|
|
|
1333
|
-
# Assigns the given
|
|
1334
|
-
#
|
|
1335
|
-
#
|
|
1523
|
+
# Assigns the given `value` to the `params` hash. If `value` is a Hash, this
|
|
1524
|
+
# will create an ActionController::Parameters object that has been instantiated
|
|
1525
|
+
# with the given `value` hash.
|
|
1336
1526
|
def params=(value)
|
|
1337
1527
|
@_params = value.is_a?(Hash) ? Parameters.new(value) : value
|
|
1338
1528
|
end
|