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