actionpack 4.2.11.3 → 5.0.7.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +890 -384
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -3
- data/lib/abstract_controller/base.rb +28 -38
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +51 -11
- data/lib/abstract_controller/caching.rb +62 -0
- data/lib/abstract_controller/callbacks.rb +54 -19
- data/lib/abstract_controller/collector.rb +4 -9
- data/lib/abstract_controller/error.rb +4 -0
- data/lib/abstract_controller/helpers.rb +4 -3
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -2
- data/lib/abstract_controller/rendering.rb +28 -18
- data/lib/abstract_controller/translation.rb +8 -7
- data/lib/abstract_controller.rb +6 -2
- data/lib/action_controller/api/api_rendering.rb +14 -0
- data/lib/action_controller/api.rb +147 -0
- data/lib/action_controller/base.rb +14 -11
- data/lib/action_controller/caching.rb +13 -58
- data/lib/action_controller/form_builder.rb +48 -0
- data/lib/action_controller/log_subscriber.rb +3 -10
- data/lib/action_controller/metal/basic_implicit_render.rb +11 -0
- data/lib/action_controller/metal/conditional_get.rb +106 -34
- data/lib/action_controller/metal/cookies.rb +1 -3
- data/lib/action_controller/metal/data_streaming.rb +14 -34
- data/lib/action_controller/metal/etag_with_template_digest.rb +8 -2
- data/lib/action_controller/metal/exceptions.rb +11 -6
- data/lib/action_controller/metal/force_ssl.rb +11 -11
- data/lib/action_controller/metal/head.rb +14 -8
- data/lib/action_controller/metal/helpers.rb +15 -6
- data/lib/action_controller/metal/http_authentication.rb +44 -35
- data/lib/action_controller/metal/implicit_render.rb +61 -6
- data/lib/action_controller/metal/instrumentation.rb +5 -5
- data/lib/action_controller/metal/live.rb +71 -88
- data/lib/action_controller/metal/mime_responds.rb +27 -42
- data/lib/action_controller/metal/params_wrapper.rb +9 -9
- data/lib/action_controller/metal/redirecting.rb +32 -9
- data/lib/action_controller/metal/renderers.rb +83 -40
- data/lib/action_controller/metal/rendering.rb +38 -6
- data/lib/action_controller/metal/request_forgery_protection.rb +126 -48
- data/lib/action_controller/metal/rescue.rb +3 -12
- data/lib/action_controller/metal/streaming.rb +4 -4
- data/lib/action_controller/metal/strong_parameters.rb +527 -134
- data/lib/action_controller/metal/testing.rb +1 -12
- data/lib/action_controller/metal/url_for.rb +12 -5
- data/lib/action_controller/metal.rb +88 -63
- data/lib/action_controller/railtie.rb +11 -7
- data/lib/action_controller/renderer.rb +113 -0
- data/lib/action_controller/template_assertions.rb +9 -0
- data/lib/action_controller/test_case.rb +311 -374
- data/lib/action_controller.rb +12 -9
- data/lib/action_dispatch/http/cache.rb +73 -34
- data/lib/action_dispatch/http/filter_parameters.rb +16 -12
- data/lib/action_dispatch/http/filter_redirect.rb +7 -8
- data/lib/action_dispatch/http/headers.rb +45 -14
- data/lib/action_dispatch/http/mime_negotiation.rb +42 -23
- data/lib/action_dispatch/http/mime_type.rb +126 -90
- data/lib/action_dispatch/http/mime_types.rb +3 -4
- data/lib/action_dispatch/http/parameter_filter.rb +19 -9
- data/lib/action_dispatch/http/parameters.rb +70 -40
- data/lib/action_dispatch/http/request.rb +144 -89
- data/lib/action_dispatch/http/response.rb +215 -102
- data/lib/action_dispatch/http/upload.rb +6 -2
- data/lib/action_dispatch/http/url.rb +117 -8
- data/lib/action_dispatch/journey/formatter.rb +47 -30
- data/lib/action_dispatch/journey/gtg/transition_table.rb +1 -1
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -2
- data/lib/action_dispatch/journey/nfa/transition_table.rb +1 -46
- data/lib/action_dispatch/journey/nodes/node.rb +14 -4
- data/lib/action_dispatch/journey/parser.rb +2 -0
- data/lib/action_dispatch/journey/parser_extras.rb +8 -2
- data/lib/action_dispatch/journey/path/pattern.rb +38 -42
- data/lib/action_dispatch/journey/route.rb +88 -26
- data/lib/action_dispatch/journey/router/utils.rb +5 -5
- data/lib/action_dispatch/journey/router.rb +8 -10
- data/lib/action_dispatch/journey/routes.rb +14 -15
- data/lib/action_dispatch/journey/visitors.rb +89 -44
- data/lib/action_dispatch/middleware/callbacks.rb +10 -1
- data/lib/action_dispatch/middleware/cookies.rb +188 -134
- data/lib/action_dispatch/middleware/debug_exceptions.rb +128 -49
- data/lib/action_dispatch/middleware/debug_locks.rb +122 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +21 -21
- data/lib/action_dispatch/middleware/executor.rb +19 -0
- data/lib/action_dispatch/middleware/flash.rb +66 -45
- data/lib/action_dispatch/middleware/params_parser.rb +32 -46
- data/lib/action_dispatch/middleware/public_exceptions.rb +2 -2
- data/lib/action_dispatch/middleware/reloader.rb +14 -58
- data/lib/action_dispatch/middleware/remote_ip.rb +29 -19
- data/lib/action_dispatch/middleware/request_id.rb +11 -6
- data/lib/action_dispatch/middleware/session/abstract_store.rb +23 -11
- data/lib/action_dispatch/middleware/session/cache_store.rb +9 -6
- data/lib/action_dispatch/middleware/session/cookie_store.rb +30 -24
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +4 -0
- data/lib/action_dispatch/middleware/show_exceptions.rb +11 -9
- data/lib/action_dispatch/middleware/ssl.rb +124 -36
- data/lib/action_dispatch/middleware/stack.rb +44 -40
- data/lib/action_dispatch/middleware/static.rb +51 -35
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +59 -63
- data/lib/action_dispatch/railtie.rb +2 -2
- data/lib/action_dispatch/request/session.rb +69 -33
- data/lib/action_dispatch/request/utils.rb +51 -19
- data/lib/action_dispatch/routing/inspector.rb +32 -43
- data/lib/action_dispatch/routing/mapper.rb +515 -348
- data/lib/action_dispatch/routing/polymorphic_routes.rb +8 -14
- data/lib/action_dispatch/routing/redirection.rb +5 -4
- data/lib/action_dispatch/routing/route_set.rb +148 -240
- data/lib/action_dispatch/routing/url_for.rb +27 -10
- data/lib/action_dispatch/routing.rb +17 -13
- data/lib/action_dispatch/testing/assertion_response.rb +45 -0
- data/lib/action_dispatch/testing/assertions/response.rb +38 -20
- data/lib/action_dispatch/testing/assertions/routing.rb +16 -12
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/integration.rb +377 -149
- data/lib/action_dispatch/testing/request_encoder.rb +53 -0
- data/lib/action_dispatch/testing/test_process.rb +24 -20
- data/lib/action_dispatch/testing/test_request.rb +22 -31
- data/lib/action_dispatch/testing/test_response.rb +12 -4
- data/lib/action_dispatch.rb +4 -1
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack.rb +1 -1
- metadata +32 -34
- data/lib/action_controller/metal/hide_actions.rb +0 -40
- data/lib/action_controller/metal/rack_delegation.rb +0 -32
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/model_naming.rb +0 -12
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
- /data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
@@ -1,20 +1,23 @@
|
|
1
1
|
require 'active_support/core_ext/hash/indifferent_access'
|
2
|
+
require 'active_support/core_ext/hash/transform_values'
|
2
3
|
require 'active_support/core_ext/array/wrap'
|
3
4
|
require 'active_support/core_ext/string/filters'
|
4
|
-
require 'active_support/
|
5
|
+
require 'active_support/core_ext/object/to_query'
|
5
6
|
require 'active_support/rescuable'
|
6
7
|
require 'action_dispatch/http/upload'
|
8
|
+
require 'rack/test'
|
7
9
|
require 'stringio'
|
8
10
|
require 'set'
|
11
|
+
require 'yaml'
|
9
12
|
|
10
13
|
module ActionController
|
11
14
|
# Raised when a required parameter is missing.
|
12
15
|
#
|
13
16
|
# params = ActionController::Parameters.new(a: {})
|
14
17
|
# params.fetch(:b)
|
15
|
-
# # => ActionController::ParameterMissing: param
|
18
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty: b
|
16
19
|
# params.require(:a)
|
17
|
-
# # => ActionController::ParameterMissing: param
|
20
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty: a
|
18
21
|
class ParameterMissing < KeyError
|
19
22
|
attr_reader :param # :nodoc:
|
20
23
|
|
@@ -40,9 +43,21 @@ module ActionController
|
|
40
43
|
end
|
41
44
|
end
|
42
45
|
|
46
|
+
# Raised when a Parameters instance is not marked as permitted and
|
47
|
+
# an operation to transform it to hash is called.
|
48
|
+
#
|
49
|
+
# params = ActionController::Parameters.new(a: "123", b: "456")
|
50
|
+
# params.to_h
|
51
|
+
# # => ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
|
52
|
+
class UnfilteredParameters < ArgumentError
|
53
|
+
def initialize # :nodoc:
|
54
|
+
super("unable to convert unpermitted parameters to hash")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
43
58
|
# == Action Controller \Parameters
|
44
59
|
#
|
45
|
-
# Allows to choose which attributes should be whitelisted for mass updating
|
60
|
+
# Allows you to choose which attributes should be whitelisted for mass updating
|
46
61
|
# and thus prevent accidentally exposing that which shouldn't be exposed.
|
47
62
|
# Provides two methods for this purpose: #require and #permit. The former is
|
48
63
|
# used to mark parameters as required. The latter is used to set the parameter
|
@@ -50,15 +65,14 @@ module ActionController
|
|
50
65
|
#
|
51
66
|
# params = ActionController::Parameters.new({
|
52
67
|
# person: {
|
53
|
-
# name:
|
68
|
+
# name: "Francesco",
|
54
69
|
# age: 22,
|
55
|
-
# role:
|
70
|
+
# role: "admin"
|
56
71
|
# }
|
57
72
|
# })
|
58
73
|
#
|
59
74
|
# permitted = params.require(:person).permit(:name, :age)
|
60
|
-
# permitted # => {"name"=>"Francesco", "age"=>22}
|
61
|
-
# permitted.class # => ActionController::Parameters
|
75
|
+
# permitted # => <ActionController::Parameters {"name"=>"Francesco", "age"=>22} permitted: true>
|
62
76
|
# permitted.permitted? # => true
|
63
77
|
#
|
64
78
|
# Person.first.update!(permitted)
|
@@ -86,7 +100,7 @@ module ActionController
|
|
86
100
|
#
|
87
101
|
# params = ActionController::Parameters.new(a: "123", b: "456")
|
88
102
|
# params.permit(:c)
|
89
|
-
# # => {}
|
103
|
+
# # => <ActionController::Parameters {} permitted: true>
|
90
104
|
#
|
91
105
|
# ActionController::Parameters.action_on_unpermitted_parameters = :raise
|
92
106
|
#
|
@@ -98,16 +112,97 @@ module ActionController
|
|
98
112
|
# environment they should only be set once at boot-time and never mutated at
|
99
113
|
# runtime.
|
100
114
|
#
|
101
|
-
# <tt>ActionController::Parameters</tt>
|
102
|
-
# <tt
|
103
|
-
# that you can fetch values using either <tt>:key</tt> or <tt>"key"</tt>.
|
115
|
+
# You can fetch values of <tt>ActionController::Parameters</tt> using either
|
116
|
+
# <tt>:key</tt> or <tt>"key"</tt>.
|
104
117
|
#
|
105
|
-
# params = ActionController::Parameters.new(key:
|
118
|
+
# params = ActionController::Parameters.new(key: "value")
|
106
119
|
# params[:key] # => "value"
|
107
120
|
# params["key"] # => "value"
|
108
|
-
class Parameters
|
121
|
+
class Parameters
|
109
122
|
cattr_accessor :permit_all_parameters, instance_accessor: false
|
110
123
|
cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
|
124
|
+
cattr_accessor :raise_on_unfiltered_parameters, instance_accessor: false
|
125
|
+
|
126
|
+
##
|
127
|
+
# :method: as_json
|
128
|
+
#
|
129
|
+
# :call-seq:
|
130
|
+
# as_json(options=nil)
|
131
|
+
#
|
132
|
+
# Returns a hash that can be used as the JSON representation for the params.
|
133
|
+
|
134
|
+
##
|
135
|
+
# :method: empty?
|
136
|
+
#
|
137
|
+
# :call-seq:
|
138
|
+
# empty?()
|
139
|
+
#
|
140
|
+
# Returns true if the object has no key/value pairs.
|
141
|
+
|
142
|
+
##
|
143
|
+
# :method: has_key?
|
144
|
+
#
|
145
|
+
# :call-seq:
|
146
|
+
# has_key?(key)
|
147
|
+
#
|
148
|
+
# Returns true if the given key is present in the parameters.
|
149
|
+
|
150
|
+
##
|
151
|
+
# :method: has_value?
|
152
|
+
#
|
153
|
+
# :call-seq:
|
154
|
+
# has_value?(value)
|
155
|
+
#
|
156
|
+
# Returns true if the given value is present for some key in the parameters.
|
157
|
+
|
158
|
+
##
|
159
|
+
# :method: include?
|
160
|
+
#
|
161
|
+
# :call-seq:
|
162
|
+
# include?(key)
|
163
|
+
#
|
164
|
+
# Returns true if the given key is present in the parameters.
|
165
|
+
|
166
|
+
##
|
167
|
+
# :method: key?
|
168
|
+
#
|
169
|
+
# :call-seq:
|
170
|
+
# key?(key)
|
171
|
+
#
|
172
|
+
# Returns true if the given key is present in the parameters.
|
173
|
+
|
174
|
+
##
|
175
|
+
# :method: keys
|
176
|
+
#
|
177
|
+
# :call-seq:
|
178
|
+
# keys()
|
179
|
+
#
|
180
|
+
# Returns a new array of the keys of the parameters.
|
181
|
+
|
182
|
+
##
|
183
|
+
# :method: to_s
|
184
|
+
#
|
185
|
+
# :call-seq:
|
186
|
+
# to_s()
|
187
|
+
# Returns the content of the parameters as a string.
|
188
|
+
|
189
|
+
##
|
190
|
+
# :method: value?
|
191
|
+
#
|
192
|
+
# :call-seq:
|
193
|
+
# value?(value)
|
194
|
+
#
|
195
|
+
# Returns true if the given value is present for some key in the parameters.
|
196
|
+
|
197
|
+
##
|
198
|
+
# :method: values
|
199
|
+
#
|
200
|
+
# :call-seq:
|
201
|
+
# values()
|
202
|
+
#
|
203
|
+
# Returns a new array of the values of the parameters.
|
204
|
+
delegate :keys, :key?, :has_key?, :values, :has_value?, :value?, :empty?, :include?,
|
205
|
+
:as_json, :to_s, to: :@parameters
|
111
206
|
|
112
207
|
# By default, never raise an UnpermittedParameters exception if these
|
113
208
|
# params are present. The default includes both 'controller' and 'action'
|
@@ -119,16 +214,6 @@ module ActionController
|
|
119
214
|
cattr_accessor :always_permitted_parameters
|
120
215
|
self.always_permitted_parameters = %w( controller action )
|
121
216
|
|
122
|
-
def self.const_missing(const_name)
|
123
|
-
super unless const_name == :NEVER_UNPERMITTED_PARAMS
|
124
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
125
|
-
`ActionController::Parameters::NEVER_UNPERMITTED_PARAMS` has been deprecated.
|
126
|
-
Use `ActionController::Parameters.always_permitted_parameters` instead.
|
127
|
-
MSG
|
128
|
-
|
129
|
-
always_permitted_parameters
|
130
|
-
end
|
131
|
-
|
132
217
|
# Returns a new instance of <tt>ActionController::Parameters</tt>.
|
133
218
|
# Also, sets the +permitted+ attribute to the default value of
|
134
219
|
# <tt>ActionController::Parameters.permit_all_parameters</tt>.
|
@@ -136,55 +221,142 @@ module ActionController
|
|
136
221
|
# class Person < ActiveRecord::Base
|
137
222
|
# end
|
138
223
|
#
|
139
|
-
# params = ActionController::Parameters.new(name:
|
224
|
+
# params = ActionController::Parameters.new(name: "Francesco")
|
140
225
|
# params.permitted? # => false
|
141
226
|
# Person.new(params) # => ActiveModel::ForbiddenAttributesError
|
142
227
|
#
|
143
228
|
# ActionController::Parameters.permit_all_parameters = true
|
144
229
|
#
|
145
|
-
# params = ActionController::Parameters.new(name:
|
230
|
+
# params = ActionController::Parameters.new(name: "Francesco")
|
146
231
|
# params.permitted? # => true
|
147
232
|
# Person.new(params) # => #<Person id: nil, name: "Francesco">
|
148
|
-
def initialize(
|
149
|
-
|
233
|
+
def initialize(parameters = {})
|
234
|
+
@parameters = parameters.with_indifferent_access
|
150
235
|
@permitted = self.class.permit_all_parameters
|
151
236
|
end
|
152
237
|
|
153
|
-
# Returns
|
154
|
-
#
|
238
|
+
# Returns true if another +Parameters+ object contains the same content and
|
239
|
+
# permitted flag.
|
240
|
+
def ==(other)
|
241
|
+
if other.respond_to?(:permitted?)
|
242
|
+
self.permitted? == other.permitted? && self.parameters == other.parameters
|
243
|
+
elsif other.is_a?(Hash)
|
244
|
+
ActiveSupport::Deprecation.warn <<-WARNING.squish
|
245
|
+
Comparing equality between `ActionController::Parameters` and a
|
246
|
+
`Hash` is deprecated and will be removed in Rails 5.1. Please only do
|
247
|
+
comparisons between instances of `ActionController::Parameters`. If
|
248
|
+
you need to compare to a hash, first convert it using
|
249
|
+
`ActionController::Parameters#new`.
|
250
|
+
WARNING
|
251
|
+
@parameters == other.with_indifferent_access
|
252
|
+
else
|
253
|
+
@parameters == other
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
# Returns a safe <tt>ActiveSupport::HashWithIndifferentAccess</tt>
|
258
|
+
# representation of the parameters with all unpermitted keys removed.
|
155
259
|
#
|
156
260
|
# params = ActionController::Parameters.new({
|
157
|
-
# name:
|
158
|
-
# oddity:
|
261
|
+
# name: "Senjougahara Hitagi",
|
262
|
+
# oddity: "Heavy stone crab"
|
159
263
|
# })
|
160
|
-
# params.to_h
|
264
|
+
# params.to_h
|
265
|
+
# # => ActionController::UnfilteredParameters: unable to convert unfiltered parameters to hash
|
161
266
|
#
|
162
267
|
# safe_params = params.permit(:name)
|
163
268
|
# safe_params.to_h # => {"name"=>"Senjougahara Hitagi"}
|
164
269
|
def to_h
|
165
270
|
if permitted?
|
166
|
-
|
271
|
+
convert_parameters_to_hashes(@parameters, :to_h)
|
272
|
+
elsif self.class.raise_on_unfiltered_parameters
|
273
|
+
raise UnfilteredParameters
|
167
274
|
else
|
168
275
|
slice(*self.class.always_permitted_parameters).permit!.to_h
|
169
276
|
end
|
170
277
|
end
|
171
278
|
|
172
|
-
# Returns
|
279
|
+
# Returns a safe <tt>Hash</tt> representation of the parameters
|
280
|
+
# with all unpermitted keys removed.
|
281
|
+
#
|
282
|
+
# params = ActionController::Parameters.new({
|
283
|
+
# name: "Senjougahara Hitagi",
|
284
|
+
# oddity: "Heavy stone crab"
|
285
|
+
# })
|
286
|
+
# params.to_hash
|
287
|
+
# # => ActionController::UnfilteredParameters: unable to convert unfiltered parameters to hash
|
288
|
+
#
|
289
|
+
# safe_params = params.permit(:name)
|
290
|
+
# safe_params.to_hash # => {"name"=>"Senjougahara Hitagi"}
|
291
|
+
def to_hash
|
292
|
+
if self.class.raise_on_unfiltered_parameters || permitted?
|
293
|
+
to_h.to_hash
|
294
|
+
else
|
295
|
+
message = <<-DEPRECATE.squish
|
296
|
+
#to_hash unexpectedly ignores parameter filtering, and will change to enforce it in Rails 5.1.
|
297
|
+
Enable `raise_on_unfiltered_parameters` to respect parameter filtering, which is the default
|
298
|
+
in new applications. For the existing deprecated behaviour, call #to_unsafe_h instead.
|
299
|
+
DEPRECATE
|
300
|
+
ActiveSupport::Deprecation.warn(message)
|
301
|
+
|
302
|
+
@parameters.to_hash
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
# Returns a string representation of the receiver suitable for use as a URL
|
307
|
+
# query string:
|
308
|
+
#
|
309
|
+
# params = ActionController::Parameters.new({
|
310
|
+
# name: "David",
|
311
|
+
# nationality: "Danish"
|
312
|
+
# })
|
313
|
+
# params.to_query
|
314
|
+
# # => "name=David&nationality=Danish"
|
315
|
+
#
|
316
|
+
# An optional namespace can be passed to enclose key names:
|
317
|
+
#
|
318
|
+
# params = ActionController::Parameters.new({
|
319
|
+
# name: "David",
|
320
|
+
# nationality: "Danish"
|
321
|
+
# })
|
322
|
+
# params.to_query("user")
|
323
|
+
# # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
|
324
|
+
#
|
325
|
+
# The string pairs "key=value" that conform the query string
|
326
|
+
# are sorted lexicographically in ascending order.
|
327
|
+
#
|
328
|
+
# This method is also aliased as +to_param+.
|
329
|
+
def to_query(*args)
|
330
|
+
if self.class.raise_on_unfiltered_parameters
|
331
|
+
to_h.to_query(*args)
|
332
|
+
else
|
333
|
+
@parameters.to_query(*args)
|
334
|
+
end
|
335
|
+
end
|
336
|
+
alias_method :to_param, :to_query
|
337
|
+
|
338
|
+
# Returns an unsafe, unfiltered
|
339
|
+
# <tt>ActiveSupport::HashWithIndifferentAccess</tt> representation of the
|
340
|
+
# parameters.
|
341
|
+
#
|
342
|
+
# params = ActionController::Parameters.new({
|
343
|
+
# name: "Senjougahara Hitagi",
|
344
|
+
# oddity: "Heavy stone crab"
|
345
|
+
# })
|
346
|
+
# params.to_unsafe_h
|
347
|
+
# # => {"name"=>"Senjougahara Hitagi", "oddity" => "Heavy stone crab"}
|
173
348
|
def to_unsafe_h
|
174
|
-
|
349
|
+
convert_parameters_to_hashes(@parameters, :to_unsafe_h)
|
175
350
|
end
|
176
351
|
alias_method :to_unsafe_hash, :to_unsafe_h
|
177
352
|
|
178
|
-
# Convert all hashes in values into parameters, then yield each pair
|
353
|
+
# Convert all hashes in values into parameters, then yield each pair in
|
179
354
|
# the same way as <tt>Hash#each_pair</tt>
|
180
355
|
def each_pair(&block)
|
181
|
-
|
182
|
-
convert_hashes_to_parameters(key, value)
|
356
|
+
@parameters.each_pair do |key, value|
|
357
|
+
yield key, convert_hashes_to_parameters(key, value)
|
183
358
|
end
|
184
|
-
|
185
|
-
super
|
186
359
|
end
|
187
|
-
|
188
360
|
alias_method :each, :each_pair
|
189
361
|
|
190
362
|
# Attribute that keeps track of converted arrays, if any, to avoid double
|
@@ -214,7 +386,7 @@ module ActionController
|
|
214
386
|
# class Person < ActiveRecord::Base
|
215
387
|
# end
|
216
388
|
#
|
217
|
-
# params = ActionController::Parameters.new(name:
|
389
|
+
# params = ActionController::Parameters.new(name: "Francesco")
|
218
390
|
# params.permitted? # => false
|
219
391
|
# Person.new(params) # => ActiveModel::ForbiddenAttributesError
|
220
392
|
# params.permit!
|
@@ -231,19 +403,58 @@ module ActionController
|
|
231
403
|
self
|
232
404
|
end
|
233
405
|
|
234
|
-
#
|
235
|
-
#
|
236
|
-
#
|
406
|
+
# This method accepts both a single key and an array of keys.
|
407
|
+
#
|
408
|
+
# When passed a single key, if it exists and its associated value is
|
409
|
+
# either present or the singleton +false+, returns said value:
|
410
|
+
#
|
411
|
+
# ActionController::Parameters.new(person: { name: "Francesco" }).require(:person)
|
412
|
+
# # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
237
413
|
#
|
238
|
-
#
|
239
|
-
#
|
414
|
+
# Otherwise raises <tt>ActionController::ParameterMissing</tt>:
|
415
|
+
#
|
416
|
+
# ActionController::Parameters.new.require(:person)
|
417
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty: person
|
240
418
|
#
|
241
419
|
# ActionController::Parameters.new(person: nil).require(:person)
|
242
|
-
# #
|
420
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty: person
|
421
|
+
#
|
422
|
+
# ActionController::Parameters.new(person: "\t").require(:person)
|
423
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty: person
|
243
424
|
#
|
244
425
|
# ActionController::Parameters.new(person: {}).require(:person)
|
245
|
-
# #
|
426
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty: person
|
427
|
+
#
|
428
|
+
# When given an array of keys, the method tries to require each one of them
|
429
|
+
# in order. If it succeeds, an array with the respective return values is
|
430
|
+
# returned:
|
431
|
+
#
|
432
|
+
# params = ActionController::Parameters.new(user: { ... }, profile: { ... })
|
433
|
+
# user_params, profile_params = params.require([:user, :profile])
|
434
|
+
#
|
435
|
+
# Otherwise, the method re-raises the first exception found:
|
436
|
+
#
|
437
|
+
# params = ActionController::Parameters.new(user: {}, profile: {})
|
438
|
+
# user_params, profile_params = params.require([:user, :profile])
|
439
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty: user
|
440
|
+
#
|
441
|
+
# Technically this method can be used to fetch terminal values:
|
442
|
+
#
|
443
|
+
# # CAREFUL
|
444
|
+
# params = ActionController::Parameters.new(person: { name: "Finn" })
|
445
|
+
# name = params.require(:person).require(:name) # CAREFUL
|
446
|
+
#
|
447
|
+
# but take into account that at some point those ones have to be permitted:
|
448
|
+
#
|
449
|
+
# def person_params
|
450
|
+
# params.require(:person).permit(:name).tap do |person_params|
|
451
|
+
# person_params.require(:name) # SAFER
|
452
|
+
# end
|
453
|
+
# end
|
454
|
+
#
|
455
|
+
# for example.
|
246
456
|
def require(key)
|
457
|
+
return key.map { |k| require(k) } if key.is_a?(Array)
|
247
458
|
value = self[key]
|
248
459
|
if value.present? || value == false
|
249
460
|
value
|
@@ -260,7 +471,7 @@ module ActionController
|
|
260
471
|
# for the object to +true+. This is useful for limiting which attributes
|
261
472
|
# should be allowed for mass updating.
|
262
473
|
#
|
263
|
-
# params = ActionController::Parameters.new(user: { name:
|
474
|
+
# params = ActionController::Parameters.new(user: { name: "Francesco", age: 22, role: "admin" })
|
264
475
|
# permitted = params.require(:user).permit(:name, :age)
|
265
476
|
# permitted.permitted? # => true
|
266
477
|
# permitted.has_key?(:name) # => true
|
@@ -271,7 +482,7 @@ module ActionController
|
|
271
482
|
#
|
272
483
|
# params.permit(:name)
|
273
484
|
#
|
274
|
-
# +:name+ passes it is a key of +params+ whose associated value is of type
|
485
|
+
# +:name+ passes if it is a key of +params+ whose associated value is of type
|
275
486
|
# +String+, +Symbol+, +NilClass+, +Numeric+, +TrueClass+, +FalseClass+,
|
276
487
|
# +Date+, +Time+, +DateTime+, +StringIO+, +IO+,
|
277
488
|
# +ActionDispatch::Http::UploadedFile+ or +Rack::Test::UploadedFile+.
|
@@ -280,18 +491,18 @@ module ActionController
|
|
280
491
|
# You may declare that the parameter should be an array of permitted scalars
|
281
492
|
# by mapping it to an empty array:
|
282
493
|
#
|
283
|
-
# params = ActionController::Parameters.new(tags: [
|
494
|
+
# params = ActionController::Parameters.new(tags: ["rails", "parameters"])
|
284
495
|
# params.permit(tags: [])
|
285
496
|
#
|
286
497
|
# You can also use +permit+ on nested parameters, like:
|
287
498
|
#
|
288
499
|
# params = ActionController::Parameters.new({
|
289
500
|
# person: {
|
290
|
-
# name:
|
501
|
+
# name: "Francesco",
|
291
502
|
# age: 22,
|
292
503
|
# pets: [{
|
293
|
-
# name:
|
294
|
-
# category:
|
504
|
+
# name: "Purplish",
|
505
|
+
# category: "dogs"
|
295
506
|
# }]
|
296
507
|
# }
|
297
508
|
# })
|
@@ -310,20 +521,20 @@ module ActionController
|
|
310
521
|
# params = ActionController::Parameters.new({
|
311
522
|
# person: {
|
312
523
|
# contact: {
|
313
|
-
# email:
|
314
|
-
# phone:
|
524
|
+
# email: "none@test.com",
|
525
|
+
# phone: "555-1234"
|
315
526
|
# }
|
316
527
|
# }
|
317
528
|
# })
|
318
529
|
#
|
319
530
|
# params.require(:person).permit(:contact)
|
320
|
-
# # => {}
|
531
|
+
# # => <ActionController::Parameters {} permitted: true>
|
321
532
|
#
|
322
533
|
# params.require(:person).permit(contact: :phone)
|
323
|
-
# # => {"contact"
|
534
|
+
# # => <ActionController::Parameters {"contact"=><ActionController::Parameters {"phone"=>"555-1234"} permitted: true>} permitted: true>
|
324
535
|
#
|
325
536
|
# params.require(:person).permit(contact: [ :email, :phone ])
|
326
|
-
# # => {"contact"
|
537
|
+
# # => <ActionController::Parameters {"contact"=><ActionController::Parameters {"email"=>"none@test.com", "phone"=>"555-1234"} permitted: true>} permitted: true>
|
327
538
|
def permit(*filters)
|
328
539
|
params = self.class.new
|
329
540
|
|
@@ -344,11 +555,17 @@ module ActionController
|
|
344
555
|
# Returns a parameter for the given +key+. If not found,
|
345
556
|
# returns +nil+.
|
346
557
|
#
|
347
|
-
# params = ActionController::Parameters.new(person: { name:
|
348
|
-
# params[:person] # => {"name"=>"Francesco"}
|
558
|
+
# params = ActionController::Parameters.new(person: { name: "Francesco" })
|
559
|
+
# params[:person] # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
349
560
|
# params[:none] # => nil
|
350
561
|
def [](key)
|
351
|
-
convert_hashes_to_parameters(key,
|
562
|
+
convert_hashes_to_parameters(key, @parameters[key])
|
563
|
+
end
|
564
|
+
|
565
|
+
# Assigns a value to a given +key+. The given key may still get filtered out
|
566
|
+
# when +permit+ is called.
|
567
|
+
def []=(key, value)
|
568
|
+
@parameters[key] = value
|
352
569
|
end
|
353
570
|
|
354
571
|
# Returns a parameter for the given +key+. If the +key+
|
@@ -357,15 +574,36 @@ module ActionController
|
|
357
574
|
# if more arguments are given, then that will be returned; if a block
|
358
575
|
# is given, then that will be run and its result returned.
|
359
576
|
#
|
360
|
-
# params = ActionController::Parameters.new(person: { name:
|
361
|
-
# params.fetch(:person) # => {"name"=>"Francesco"}
|
362
|
-
# params.fetch(:none) # => ActionController::ParameterMissing: param
|
363
|
-
# params.fetch(:none,
|
364
|
-
# params.fetch(:none) {
|
577
|
+
# params = ActionController::Parameters.new(person: { name: "Francesco" })
|
578
|
+
# params.fetch(:person) # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
579
|
+
# params.fetch(:none) # => ActionController::ParameterMissing: param is missing or the value is empty: none
|
580
|
+
# params.fetch(:none, "Francesco") # => "Francesco"
|
581
|
+
# params.fetch(:none) { "Francesco" } # => "Francesco"
|
365
582
|
def fetch(key, *args)
|
366
|
-
|
367
|
-
|
368
|
-
|
583
|
+
convert_value_to_parameters(
|
584
|
+
@parameters.fetch(key) {
|
585
|
+
if block_given?
|
586
|
+
yield
|
587
|
+
else
|
588
|
+
args.fetch(0) { raise ActionController::ParameterMissing.new(key) }
|
589
|
+
end
|
590
|
+
}
|
591
|
+
)
|
592
|
+
end
|
593
|
+
|
594
|
+
if Hash.method_defined?(:dig)
|
595
|
+
# Extracts the nested parameter from the given +keys+ by calling +dig+
|
596
|
+
# at each step. Returns +nil+ if any intermediate step is +nil+.
|
597
|
+
#
|
598
|
+
# params = ActionController::Parameters.new(foo: { bar: { baz: 1 } })
|
599
|
+
# params.dig(:foo, :bar, :baz) # => 1
|
600
|
+
# params.dig(:foo, :zot, :xyz) # => nil
|
601
|
+
#
|
602
|
+
# params2 = ActionController::Parameters.new(foo: [10, 11, 12])
|
603
|
+
# params2.dig(:foo, 1) # => 11
|
604
|
+
def dig(*keys)
|
605
|
+
convert_value_to_parameters(@parameters.dig(*keys))
|
606
|
+
end
|
369
607
|
end
|
370
608
|
|
371
609
|
# Returns a new <tt>ActionController::Parameters</tt> instance that
|
@@ -373,19 +611,36 @@ module ActionController
|
|
373
611
|
# don't exist, returns an empty hash.
|
374
612
|
#
|
375
613
|
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
376
|
-
# params.slice(:a, :b) # => {"a"=>1, "b"=>2}
|
377
|
-
# params.slice(:d) # => {}
|
614
|
+
# params.slice(:a, :b) # => <ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
|
615
|
+
# params.slice(:d) # => <ActionController::Parameters {} permitted: false>
|
378
616
|
def slice(*keys)
|
379
|
-
new_instance_with_inherited_permitted_status(
|
617
|
+
new_instance_with_inherited_permitted_status(@parameters.slice(*keys))
|
618
|
+
end
|
619
|
+
|
620
|
+
# Returns current <tt>ActionController::Parameters</tt> instance which
|
621
|
+
# contains only the given +keys+.
|
622
|
+
def slice!(*keys)
|
623
|
+
@parameters.slice!(*keys)
|
624
|
+
self
|
625
|
+
end
|
626
|
+
|
627
|
+
# Returns a new <tt>ActionController::Parameters</tt> instance that
|
628
|
+
# filters out the given +keys+.
|
629
|
+
#
|
630
|
+
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
631
|
+
# params.except(:a, :b) # => <ActionController::Parameters {"c"=>3} permitted: false>
|
632
|
+
# params.except(:d) # => <ActionController::Parameters {"a"=>1, "b"=>2, "c"=>3} permitted: false>
|
633
|
+
def except(*keys)
|
634
|
+
new_instance_with_inherited_permitted_status(@parameters.except(*keys))
|
380
635
|
end
|
381
636
|
|
382
637
|
# Removes and returns the key/value pairs matching the given keys.
|
383
638
|
#
|
384
639
|
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
385
|
-
# params.extract!(:a, :b) # => {"a"=>1, "b"=>2}
|
386
|
-
# params # => {"c"=>3}
|
640
|
+
# params.extract!(:a, :b) # => <ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
|
641
|
+
# params # => <ActionController::Parameters {"c"=>3} permitted: false>
|
387
642
|
def extract!(*keys)
|
388
|
-
new_instance_with_inherited_permitted_status(
|
643
|
+
new_instance_with_inherited_permitted_status(@parameters.extract!(*keys))
|
389
644
|
end
|
390
645
|
|
391
646
|
# Returns a new <tt>ActionController::Parameters</tt> with the results of
|
@@ -393,58 +648,176 @@ module ActionController
|
|
393
648
|
#
|
394
649
|
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
395
650
|
# params.transform_values { |x| x * 2 }
|
396
|
-
# # => {"a"=>2, "b"=>4, "c"=>6}
|
397
|
-
def transform_values
|
398
|
-
if
|
399
|
-
new_instance_with_inherited_permitted_status(
|
651
|
+
# # => <ActionController::Parameters {"a"=>2, "b"=>4, "c"=>6} permitted: false>
|
652
|
+
def transform_values(&block)
|
653
|
+
if block
|
654
|
+
new_instance_with_inherited_permitted_status(
|
655
|
+
@parameters.transform_values(&block)
|
656
|
+
)
|
400
657
|
else
|
401
|
-
|
658
|
+
@parameters.transform_values
|
402
659
|
end
|
403
660
|
end
|
404
661
|
|
405
|
-
#
|
406
|
-
#
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
662
|
+
# Performs values transformation and returns the altered
|
663
|
+
# <tt>ActionController::Parameters</tt> instance.
|
664
|
+
def transform_values!(&block)
|
665
|
+
@parameters.transform_values!(&block)
|
666
|
+
self
|
667
|
+
end
|
668
|
+
|
669
|
+
# Returns a new <tt>ActionController::Parameters</tt> instance with the
|
670
|
+
# results of running +block+ once for every key. The values are unchanged.
|
671
|
+
def transform_keys(&block)
|
672
|
+
if block
|
673
|
+
new_instance_with_inherited_permitted_status(
|
674
|
+
@parameters.transform_keys(&block)
|
675
|
+
)
|
411
676
|
else
|
412
|
-
|
677
|
+
@parameters.transform_keys
|
413
678
|
end
|
414
679
|
end
|
415
680
|
|
681
|
+
# Performs keys transformation and returns the altered
|
682
|
+
# <tt>ActionController::Parameters</tt> instance.
|
683
|
+
def transform_keys!(&block)
|
684
|
+
@parameters.transform_keys!(&block)
|
685
|
+
self
|
686
|
+
end
|
687
|
+
|
416
688
|
# Deletes and returns a key-value pair from +Parameters+ whose key is equal
|
417
689
|
# to key. If the key is not found, returns the default value. If the
|
418
690
|
# optional code block is given and the key is not found, pass in the key
|
419
691
|
# and return the result of block.
|
420
692
|
def delete(key, &block)
|
421
|
-
|
693
|
+
convert_value_to_parameters(@parameters.delete(key, &block))
|
694
|
+
end
|
695
|
+
|
696
|
+
# Returns a new instance of <tt>ActionController::Parameters</tt> with only
|
697
|
+
# items that the block evaluates to true.
|
698
|
+
def select(&block)
|
699
|
+
new_instance_with_inherited_permitted_status(@parameters.select(&block))
|
422
700
|
end
|
423
701
|
|
424
702
|
# Equivalent to Hash#keep_if, but returns nil if no changes were made.
|
425
703
|
def select!(&block)
|
426
|
-
|
704
|
+
@parameters.select!(&block)
|
705
|
+
self
|
427
706
|
end
|
707
|
+
alias_method :keep_if, :select!
|
428
708
|
|
429
|
-
# Returns
|
430
|
-
#
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
#
|
436
|
-
|
437
|
-
|
438
|
-
|
709
|
+
# Returns a new instance of <tt>ActionController::Parameters</tt> with items
|
710
|
+
# that the block evaluates to true removed.
|
711
|
+
def reject(&block)
|
712
|
+
new_instance_with_inherited_permitted_status(@parameters.reject(&block))
|
713
|
+
end
|
714
|
+
|
715
|
+
# Removes items that the block evaluates to true and returns self.
|
716
|
+
def reject!(&block)
|
717
|
+
@parameters.reject!(&block)
|
718
|
+
self
|
719
|
+
end
|
720
|
+
alias_method :delete_if, :reject!
|
721
|
+
|
722
|
+
# Returns values that were assigned to the given +keys+. Note that all the
|
723
|
+
# +Hash+ objects will be converted to <tt>ActionController::Parameters</tt>.
|
724
|
+
def values_at(*keys)
|
725
|
+
convert_value_to_parameters(@parameters.values_at(*keys))
|
726
|
+
end
|
727
|
+
|
728
|
+
# Returns a new <tt>ActionController::Parameters</tt> with all keys from
|
729
|
+
# +other_hash+ merges into current hash.
|
730
|
+
def merge(other_hash)
|
731
|
+
new_instance_with_inherited_permitted_status(
|
732
|
+
@parameters.merge(other_hash.to_h)
|
733
|
+
)
|
734
|
+
end
|
735
|
+
|
736
|
+
# Returns current <tt>ActionController::Parameters</tt> instance which
|
737
|
+
# +other_hash+ merges into current hash.
|
738
|
+
def merge!(other_hash)
|
739
|
+
@parameters.merge!(other_hash.to_h)
|
740
|
+
self
|
741
|
+
end
|
742
|
+
|
743
|
+
# This is required by ActiveModel attribute assignment, so that user can
|
744
|
+
# pass +Parameters+ to a mass assignment methods in a model. It should not
|
745
|
+
# matter as we are using +HashWithIndifferentAccess+ internally.
|
746
|
+
def stringify_keys # :nodoc:
|
747
|
+
dup
|
748
|
+
end
|
749
|
+
|
750
|
+
def inspect
|
751
|
+
"<#{self.class} #{@parameters} permitted: #{@permitted}>"
|
752
|
+
end
|
753
|
+
|
754
|
+
def self.hook_into_yaml_loading # :nodoc:
|
755
|
+
# Wire up YAML format compatibility with Rails 4.2 and Psych 2.0.8 and 2.0.9+.
|
756
|
+
# Makes the YAML parser call `init_with` when it encounters the keys below
|
757
|
+
# instead of trying its own parsing routines.
|
758
|
+
YAML.load_tags['!ruby/hash-with-ivars:ActionController::Parameters'] = name
|
759
|
+
YAML.load_tags['!ruby/hash:ActionController::Parameters'] = name
|
760
|
+
end
|
761
|
+
hook_into_yaml_loading
|
762
|
+
|
763
|
+
def init_with(coder) # :nodoc:
|
764
|
+
case coder.tag
|
765
|
+
when '!ruby/hash:ActionController::Parameters'
|
766
|
+
# YAML 2.0.8's format where hash instance variables weren't stored.
|
767
|
+
@parameters = coder.map.with_indifferent_access
|
768
|
+
@permitted = false
|
769
|
+
when '!ruby/hash-with-ivars:ActionController::Parameters'
|
770
|
+
# YAML 2.0.9's Hash subclass format where keys and values
|
771
|
+
# were stored under an elements hash and `permitted` within an ivars hash.
|
772
|
+
@parameters = coder.map['elements'].with_indifferent_access
|
773
|
+
@permitted = coder.map['ivars'][:@permitted]
|
774
|
+
when '!ruby/object:ActionController::Parameters'
|
775
|
+
# YAML's Object format. Only needed because of the format
|
776
|
+
# backwardscompability above, otherwise equivalent to YAML's initialization.
|
777
|
+
@parameters, @permitted = coder.map['parameters'], coder.map['permitted']
|
778
|
+
end
|
779
|
+
end
|
780
|
+
|
781
|
+
def method_missing(method_sym, *args, &block)
|
782
|
+
if @parameters.respond_to?(method_sym)
|
783
|
+
message = <<-DEPRECATE.squish
|
784
|
+
Method #{method_sym} is deprecated and will be removed in Rails 5.1,
|
785
|
+
as `ActionController::Parameters` no longer inherits from
|
786
|
+
hash. Using this deprecated behavior exposes potential security
|
787
|
+
problems. If you continue to use this method you may be creating
|
788
|
+
a security vulnerability in your app that can be exploited. Instead,
|
789
|
+
consider using one of these documented methods which are not
|
790
|
+
deprecated: http://api.rubyonrails.org/v#{ActionPack.version}/classes/ActionController/Parameters.html
|
791
|
+
DEPRECATE
|
792
|
+
ActiveSupport::Deprecation.warn(message)
|
793
|
+
@parameters.public_send(method_sym, *args, &block)
|
794
|
+
else
|
795
|
+
super
|
796
|
+
end
|
797
|
+
end
|
798
|
+
|
799
|
+
def respond_to?(name, include_all = false) # :nodoc:
|
800
|
+
super || @parameters.respond_to?(name, include_all)
|
801
|
+
end
|
802
|
+
|
803
|
+
# Returns duplicate of object including all parameters.
|
804
|
+
def deep_dup
|
805
|
+
self.class.new(@parameters.deep_dup).tap do |duplicate|
|
439
806
|
duplicate.permitted = @permitted
|
440
807
|
end
|
441
808
|
end
|
442
809
|
|
443
810
|
protected
|
811
|
+
attr_reader :parameters
|
812
|
+
|
444
813
|
def permitted=(new_permitted)
|
445
814
|
@permitted = new_permitted
|
446
815
|
end
|
447
816
|
|
817
|
+
def fields_for_style?
|
818
|
+
@parameters.all? { |k, v| k =~ /\A-?\d+\z/ && (v.is_a?(Hash) || v.is_a?(Parameters)) }
|
819
|
+
end
|
820
|
+
|
448
821
|
private
|
449
822
|
def new_instance_with_inherited_permitted_status(hash)
|
450
823
|
self.class.new(hash).tap do |new_instance|
|
@@ -452,40 +825,56 @@ module ActionController
|
|
452
825
|
end
|
453
826
|
end
|
454
827
|
|
455
|
-
def
|
828
|
+
def convert_parameters_to_hashes(value, using)
|
829
|
+
case value
|
830
|
+
when Array
|
831
|
+
value.map { |v| convert_parameters_to_hashes(v, using) }
|
832
|
+
when Hash
|
833
|
+
value.transform_values do |v|
|
834
|
+
convert_parameters_to_hashes(v, using)
|
835
|
+
end.with_indifferent_access
|
836
|
+
when Parameters
|
837
|
+
value.send(using)
|
838
|
+
else
|
839
|
+
value
|
840
|
+
end
|
841
|
+
end
|
842
|
+
|
843
|
+
def convert_hashes_to_parameters(key, value)
|
456
844
|
converted = convert_value_to_parameters(value)
|
457
|
-
|
845
|
+
@parameters[key] = converted unless converted.equal?(value)
|
458
846
|
converted
|
459
847
|
end
|
460
848
|
|
461
849
|
def convert_value_to_parameters(value)
|
462
|
-
|
850
|
+
case value
|
851
|
+
when Array
|
852
|
+
return value if converted_arrays.member?(value)
|
463
853
|
converted = value.map { |_| convert_value_to_parameters(_) }
|
464
854
|
converted_arrays << converted
|
465
855
|
converted
|
466
|
-
|
467
|
-
value
|
468
|
-
else
|
856
|
+
when Hash
|
469
857
|
self.class.new(value)
|
858
|
+
else
|
859
|
+
value
|
470
860
|
end
|
471
861
|
end
|
472
862
|
|
473
863
|
def each_element(object)
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
object.
|
479
|
-
|
480
|
-
|
481
|
-
|
864
|
+
case object
|
865
|
+
when Array
|
866
|
+
object.grep(Parameters).map { |el| yield el }.compact
|
867
|
+
when Parameters
|
868
|
+
if object.fields_for_style?
|
869
|
+
hash = object.class.new
|
870
|
+
object.each { |k,v| hash[k] = yield v }
|
871
|
+
hash
|
872
|
+
else
|
873
|
+
yield object
|
874
|
+
end
|
482
875
|
end
|
483
876
|
end
|
484
877
|
|
485
|
-
def fields_for_style?(object)
|
486
|
-
object.is_a?(Hash) && object.all? { |k, v| k =~ /\A-?\d+\z/ && v.is_a?(Hash) }
|
487
|
-
end
|
488
|
-
|
489
878
|
def unpermitted_parameters!(params)
|
490
879
|
unpermitted_keys = unpermitted_keys(params)
|
491
880
|
if unpermitted_keys.any?
|
@@ -547,15 +936,13 @@ module ActionController
|
|
547
936
|
end
|
548
937
|
|
549
938
|
def array_of_permitted_scalars?(value)
|
550
|
-
if value.is_a?(Array)
|
551
|
-
value
|
939
|
+
if value.is_a?(Array) && value.all? {|element| permitted_scalar?(element)}
|
940
|
+
yield value
|
552
941
|
end
|
553
942
|
end
|
554
943
|
|
555
|
-
def
|
556
|
-
|
557
|
-
params[key] = self[key]
|
558
|
-
end
|
944
|
+
def non_scalar?(value)
|
945
|
+
value.is_a?(Array) || value.is_a?(Parameters)
|
559
946
|
end
|
560
947
|
|
561
948
|
EMPTY_ARRAY = []
|
@@ -565,21 +952,26 @@ module ActionController
|
|
565
952
|
# Slicing filters out non-declared keys.
|
566
953
|
slice(*filter.keys).each do |key, value|
|
567
954
|
next unless value
|
955
|
+
next unless has_key? key
|
568
956
|
|
569
957
|
if filter[key] == EMPTY_ARRAY
|
570
958
|
# Declaration { comment_ids: [] }.
|
571
|
-
|
572
|
-
|
959
|
+
array_of_permitted_scalars?(self[key]) do |val|
|
960
|
+
params[key] = val
|
961
|
+
end
|
962
|
+
elsif non_scalar?(value)
|
573
963
|
# Declaration { user: :name } or { user: [:name, :age, { address: ... }] }.
|
574
964
|
params[key] = each_element(value) do |element|
|
575
|
-
|
576
|
-
element = self.class.new(element) unless element.respond_to?(:permit)
|
577
|
-
element.permit(*Array.wrap(filter[key]))
|
578
|
-
end
|
965
|
+
element.permit(*Array.wrap(filter[key]))
|
579
966
|
end
|
580
967
|
end
|
581
968
|
end
|
582
969
|
end
|
970
|
+
|
971
|
+
def initialize_copy(source)
|
972
|
+
super
|
973
|
+
@parameters = @parameters.dup
|
974
|
+
end
|
583
975
|
end
|
584
976
|
|
585
977
|
# == Strong \Parameters
|
@@ -623,7 +1015,8 @@ module ActionController
|
|
623
1015
|
# end
|
624
1016
|
#
|
625
1017
|
# In order to use <tt>accepts_nested_attributes_for</tt> with Strong \Parameters, you
|
626
|
-
# will need to specify which nested attributes should be whitelisted.
|
1018
|
+
# will need to specify which nested attributes should be whitelisted. You might want
|
1019
|
+
# to allow +:id+ and +:_destroy+, see ActiveRecord::NestedAttributes for more information.
|
627
1020
|
#
|
628
1021
|
# class Person
|
629
1022
|
# has_many :pets
|
@@ -643,7 +1036,7 @@ module ActionController
|
|
643
1036
|
# # It's mandatory to specify the nested attributes that should be whitelisted.
|
644
1037
|
# # If you use `permit` with just the key that points to the nested attributes hash,
|
645
1038
|
# # it will return an empty hash.
|
646
|
-
# params.require(:person).permit(:name, :age, pets_attributes: [ :name, :category ])
|
1039
|
+
# params.require(:person).permit(:name, :age, pets_attributes: [ :id, :name, :category ])
|
647
1040
|
# end
|
648
1041
|
# end
|
649
1042
|
#
|