actionpack 5.0.7.2 → 5.1.0.beta1
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 +5 -5
- data/CHANGELOG.md +189 -1002
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/abstract_controller.rb +3 -3
- data/lib/abstract_controller/base.rb +10 -12
- data/lib/abstract_controller/caching.rb +6 -3
- data/lib/abstract_controller/caching/fragments.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +2 -43
- data/lib/abstract_controller/collector.rb +2 -2
- data/lib/abstract_controller/helpers.rb +19 -19
- data/lib/abstract_controller/rendering.rb +9 -11
- data/lib/abstract_controller/translation.rb +3 -3
- data/lib/action_controller.rb +15 -13
- data/lib/action_controller/api.rb +3 -3
- data/lib/action_controller/base.rb +7 -12
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +2 -2
- data/lib/action_controller/metal.rb +34 -43
- data/lib/action_controller/metal/conditional_get.rb +10 -9
- data/lib/action_controller/metal/data_streaming.rb +8 -9
- data/lib/action_controller/metal/etag_with_flash.rb +16 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +15 -15
- data/lib/action_controller/metal/exceptions.rb +4 -14
- data/lib/action_controller/metal/flash.rb +1 -1
- data/lib/action_controller/metal/force_ssl.rb +6 -6
- data/lib/action_controller/metal/head.rb +13 -19
- data/lib/action_controller/metal/helpers.rb +6 -6
- data/lib/action_controller/metal/http_authentication.rb +22 -23
- data/lib/action_controller/metal/implicit_render.rb +2 -5
- data/lib/action_controller/metal/instrumentation.rb +14 -14
- data/lib/action_controller/metal/live.rb +15 -16
- data/lib/action_controller/metal/mime_responds.rb +3 -3
- data/lib/action_controller/metal/parameter_encoding.rb +49 -0
- data/lib/action_controller/metal/params_wrapper.rb +32 -32
- data/lib/action_controller/metal/redirecting.rb +8 -24
- data/lib/action_controller/metal/renderers.rb +2 -3
- data/lib/action_controller/metal/rendering.rb +50 -60
- data/lib/action_controller/metal/request_forgery_protection.rb +51 -49
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/streaming.rb +4 -4
- data/lib/action_controller/metal/strong_parameters.rb +117 -250
- data/lib/action_controller/metal/testing.rb +1 -1
- data/lib/action_controller/metal/url_for.rb +4 -4
- data/lib/action_controller/railtie.rb +9 -13
- data/lib/action_controller/renderer.rb +17 -16
- data/lib/action_controller/test_case.rb +75 -148
- data/lib/action_dispatch.rb +20 -19
- data/lib/action_dispatch/http/cache.rb +9 -10
- data/lib/action_dispatch/http/filter_parameters.rb +8 -8
- data/lib/action_dispatch/http/filter_redirect.rb +2 -4
- data/lib/action_dispatch/http/headers.rb +10 -10
- data/lib/action_dispatch/http/mime_negotiation.rb +17 -22
- data/lib/action_dispatch/http/mime_type.rb +27 -52
- data/lib/action_dispatch/http/parameter_filter.rb +8 -6
- data/lib/action_dispatch/http/parameters.rb +40 -17
- data/lib/action_dispatch/http/request.rb +38 -34
- data/lib/action_dispatch/http/response.rb +16 -16
- data/lib/action_dispatch/http/upload.rb +6 -10
- data/lib/action_dispatch/http/url.rb +48 -74
- data/lib/action_dispatch/journey.rb +5 -5
- data/lib/action_dispatch/journey/formatter.rb +8 -4
- data/lib/action_dispatch/journey/gtg/builder.rb +5 -5
- data/lib/action_dispatch/journey/gtg/simulator.rb +1 -1
- data/lib/action_dispatch/journey/gtg/transition_table.rb +15 -15
- data/lib/action_dispatch/journey/nfa/builder.rb +3 -3
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
- data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +2 -2
- data/lib/action_dispatch/journey/nodes/node.rb +5 -5
- data/lib/action_dispatch/journey/parser.rb +23 -24
- data/lib/action_dispatch/journey/parser.y +3 -2
- data/lib/action_dispatch/journey/parser_extras.rb +2 -2
- data/lib/action_dispatch/journey/path/pattern.rb +10 -3
- data/lib/action_dispatch/journey/route.rb +19 -12
- data/lib/action_dispatch/journey/router.rb +19 -12
- data/lib/action_dispatch/journey/router/utils.rb +9 -9
- data/lib/action_dispatch/journey/scanner.rb +17 -15
- data/lib/action_dispatch/journey/visitors.rb +23 -23
- data/lib/action_dispatch/middleware/callbacks.rb +0 -12
- data/lib/action_dispatch/middleware/cookies.rb +39 -39
- data/lib/action_dispatch/middleware/debug_exceptions.rb +126 -112
- data/lib/action_dispatch/middleware/debug_locks.rb +8 -8
- data/lib/action_dispatch/middleware/exception_wrapper.rb +55 -55
- data/lib/action_dispatch/middleware/executor.rb +1 -1
- data/lib/action_dispatch/middleware/flash.rb +17 -16
- data/lib/action_dispatch/middleware/public_exceptions.rb +20 -20
- data/lib/action_dispatch/middleware/reloader.rb +3 -47
- data/lib/action_dispatch/middleware/remote_ip.rb +6 -8
- data/lib/action_dispatch/middleware/request_id.rb +6 -5
- data/lib/action_dispatch/middleware/session/abstract_store.rb +14 -26
- data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
- data/lib/action_dispatch/middleware/session/cookie_store.rb +35 -35
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +2 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +19 -19
- data/lib/action_dispatch/middleware/ssl.rb +9 -27
- data/lib/action_dispatch/middleware/stack.rb +7 -26
- data/lib/action_dispatch/middleware/static.rb +13 -24
- data/lib/action_dispatch/railtie.rb +9 -11
- data/lib/action_dispatch/request/session.rb +22 -22
- data/lib/action_dispatch/request/utils.rb +11 -2
- data/lib/action_dispatch/routing.rb +8 -6
- data/lib/action_dispatch/routing/inspector.rb +37 -37
- data/lib/action_dispatch/routing/mapper.rb +296 -203
- data/lib/action_dispatch/routing/polymorphic_routes.rb +160 -134
- data/lib/action_dispatch/routing/redirection.rb +27 -22
- data/lib/action_dispatch/routing/route_set.rb +206 -92
- data/lib/action_dispatch/routing/routes_proxy.rb +2 -2
- data/lib/action_dispatch/routing/url_for.rb +14 -12
- data/lib/action_dispatch/system_test_case.rb +119 -0
- data/lib/action_dispatch/system_testing/browser.rb +28 -0
- data/lib/action_dispatch/system_testing/driver.rb +18 -0
- data/lib/action_dispatch/system_testing/server.rb +32 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +61 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +20 -0
- data/lib/action_dispatch/testing/assertion_response.rb +6 -6
- data/lib/action_dispatch/testing/assertions.rb +4 -4
- data/lib/action_dispatch/testing/assertions/response.rb +8 -3
- data/lib/action_dispatch/testing/assertions/routing.rb +11 -11
- data/lib/action_dispatch/testing/integration.rb +47 -138
- data/lib/action_dispatch/testing/test_process.rb +2 -2
- data/lib/action_dispatch/testing/test_request.rb +16 -16
- data/lib/action_dispatch/testing/test_response.rb +1 -1
- data/lib/action_pack.rb +2 -2
- data/lib/action_pack/gem_version.rb +3 -3
- data/lib/action_pack/version.rb +1 -1
- metadata +20 -12
- data/lib/action_dispatch/middleware/params_parser.rb +0 -46
@@ -19,7 +19,7 @@ module ActionController #:nodoc:
|
|
19
19
|
def process_action(*args)
|
20
20
|
super
|
21
21
|
rescue Exception => exception
|
22
|
-
request.env[
|
22
|
+
request.env["action_dispatch.show_detailed_exceptions"] ||= show_detailed_exceptions?
|
23
23
|
rescue_with_handler(exception) || raise
|
24
24
|
end
|
25
25
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "rack/chunked"
|
2
2
|
|
3
3
|
module ActionController #:nodoc:
|
4
4
|
# Allows views to be streamed back to the client as they are rendered.
|
@@ -193,10 +193,10 @@ module ActionController #:nodoc:
|
|
193
193
|
module Streaming
|
194
194
|
extend ActiveSupport::Concern
|
195
195
|
|
196
|
-
|
196
|
+
private
|
197
197
|
|
198
198
|
# Set proper cache control and transfer encoding when streaming
|
199
|
-
def _process_options(options)
|
199
|
+
def _process_options(options)
|
200
200
|
super
|
201
201
|
if options[:stream]
|
202
202
|
if request.version == "HTTP/1.0"
|
@@ -210,7 +210,7 @@ module ActionController #:nodoc:
|
|
210
210
|
end
|
211
211
|
|
212
212
|
# Call render_body if we are streaming instead of usual +render+.
|
213
|
-
def _render_template(options)
|
213
|
+
def _render_template(options)
|
214
214
|
if options.delete(:stream)
|
215
215
|
Rack::Chunked::Body.new view_renderer.render_body(view_context, options)
|
216
216
|
else
|
@@ -1,14 +1,14 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
1
|
+
require "active_support/core_ext/hash/indifferent_access"
|
2
|
+
require "active_support/core_ext/hash/transform_values"
|
3
|
+
require "active_support/core_ext/array/wrap"
|
4
|
+
require "active_support/core_ext/string/filters"
|
5
|
+
require "active_support/core_ext/object/to_query"
|
6
|
+
require "active_support/rescuable"
|
7
|
+
require "action_dispatch/http/upload"
|
8
|
+
require "rack/test"
|
9
|
+
require "stringio"
|
10
|
+
require "set"
|
11
|
+
require "yaml"
|
12
12
|
|
13
13
|
module ActionController
|
14
14
|
# Raised when a required parameter is missing.
|
@@ -33,25 +33,13 @@ module ActionController
|
|
33
33
|
#
|
34
34
|
# params = ActionController::Parameters.new(a: "123", b: "456")
|
35
35
|
# params.permit(:c)
|
36
|
-
# # => ActionController::UnpermittedParameters: found unpermitted parameters: a, b
|
36
|
+
# # => ActionController::UnpermittedParameters: found unpermitted parameters: :a, :b
|
37
37
|
class UnpermittedParameters < IndexError
|
38
38
|
attr_reader :params # :nodoc:
|
39
39
|
|
40
40
|
def initialize(params) # :nodoc:
|
41
41
|
@params = params
|
42
|
-
super("found unpermitted parameter#{'s' if params.size > 1 }: #{params.join(", ")}")
|
43
|
-
end
|
44
|
-
end
|
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")
|
42
|
+
super("found unpermitted parameter#{'s' if params.size > 1 }: #{params.map { |e| ":#{e}" }.join(", ")}")
|
55
43
|
end
|
56
44
|
end
|
57
45
|
|
@@ -65,9 +53,9 @@ module ActionController
|
|
65
53
|
#
|
66
54
|
# params = ActionController::Parameters.new({
|
67
55
|
# person: {
|
68
|
-
# name:
|
56
|
+
# name: 'Francesco',
|
69
57
|
# age: 22,
|
70
|
-
# role:
|
58
|
+
# role: 'admin'
|
71
59
|
# }
|
72
60
|
# })
|
73
61
|
#
|
@@ -83,8 +71,8 @@ module ActionController
|
|
83
71
|
# * +permit_all_parameters+ - If it's +true+, all the parameters will be
|
84
72
|
# permitted by default. The default is +false+.
|
85
73
|
# * +action_on_unpermitted_parameters+ - Allow to control the behavior when parameters
|
86
|
-
# that are not explicitly permitted are found. The values can be
|
87
|
-
# write a message on the logger or <tt>:raise</tt> to raise
|
74
|
+
# that are not explicitly permitted are found. The values can be +false+ to just filter them
|
75
|
+
# out, <tt>:log</tt> to additionally write a message on the logger, or <tt>:raise</tt> to raise
|
88
76
|
# ActionController::UnpermittedParameters exception. The default value is <tt>:log</tt>
|
89
77
|
# in test and development environments, +false+ otherwise.
|
90
78
|
#
|
@@ -115,94 +103,17 @@ module ActionController
|
|
115
103
|
# You can fetch values of <tt>ActionController::Parameters</tt> using either
|
116
104
|
# <tt>:key</tt> or <tt>"key"</tt>.
|
117
105
|
#
|
118
|
-
# params = ActionController::Parameters.new(key:
|
106
|
+
# params = ActionController::Parameters.new(key: 'value')
|
119
107
|
# params[:key] # => "value"
|
120
108
|
# params["key"] # => "value"
|
121
109
|
class Parameters
|
122
110
|
cattr_accessor :permit_all_parameters, instance_accessor: false
|
123
|
-
|
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.
|
111
|
+
self.permit_all_parameters = false
|
149
112
|
|
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.
|
113
|
+
cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
|
196
114
|
|
197
|
-
##
|
198
|
-
# :method: values
|
199
|
-
#
|
200
|
-
# :call-seq:
|
201
|
-
# values()
|
202
|
-
#
|
203
|
-
# Returns a new array of the values of the parameters.
|
204
115
|
delegate :keys, :key?, :has_key?, :values, :has_value?, :value?, :empty?, :include?,
|
205
|
-
:as_json,
|
116
|
+
:as_json, to: :@parameters
|
206
117
|
|
207
118
|
# By default, never raise an UnpermittedParameters exception if these
|
208
119
|
# params are present. The default includes both 'controller' and 'action'
|
@@ -221,13 +132,13 @@ module ActionController
|
|
221
132
|
# class Person < ActiveRecord::Base
|
222
133
|
# end
|
223
134
|
#
|
224
|
-
# params = ActionController::Parameters.new(name:
|
135
|
+
# params = ActionController::Parameters.new(name: 'Francesco')
|
225
136
|
# params.permitted? # => false
|
226
137
|
# Person.new(params) # => ActiveModel::ForbiddenAttributesError
|
227
138
|
#
|
228
139
|
# ActionController::Parameters.permit_all_parameters = true
|
229
140
|
#
|
230
|
-
# params = ActionController::Parameters.new(name:
|
141
|
+
# params = ActionController::Parameters.new(name: 'Francesco')
|
231
142
|
# params.permitted? # => true
|
232
143
|
# Person.new(params) # => #<Person id: nil, name: "Francesco">
|
233
144
|
def initialize(parameters = {})
|
@@ -239,109 +150,38 @@ module ActionController
|
|
239
150
|
# permitted flag.
|
240
151
|
def ==(other)
|
241
152
|
if other.respond_to?(:permitted?)
|
242
|
-
|
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
|
153
|
+
permitted? == other.permitted? && parameters == other.parameters
|
252
154
|
else
|
253
155
|
@parameters == other
|
254
156
|
end
|
255
157
|
end
|
256
158
|
|
257
159
|
# Returns a safe <tt>ActiveSupport::HashWithIndifferentAccess</tt>
|
258
|
-
# representation of
|
160
|
+
# representation of this parameter with all unpermitted keys removed.
|
259
161
|
#
|
260
162
|
# params = ActionController::Parameters.new({
|
261
|
-
# name:
|
262
|
-
# oddity:
|
163
|
+
# name: 'Senjougahara Hitagi',
|
164
|
+
# oddity: 'Heavy stone crab'
|
263
165
|
# })
|
264
|
-
# params.to_h
|
265
|
-
# # => ActionController::UnfilteredParameters: unable to convert unfiltered parameters to hash
|
166
|
+
# params.to_h # => {}
|
266
167
|
#
|
267
168
|
# safe_params = params.permit(:name)
|
268
169
|
# safe_params.to_h # => {"name"=>"Senjougahara Hitagi"}
|
269
170
|
def to_h
|
270
171
|
if permitted?
|
271
172
|
convert_parameters_to_hashes(@parameters, :to_h)
|
272
|
-
elsif self.class.raise_on_unfiltered_parameters
|
273
|
-
raise UnfilteredParameters
|
274
173
|
else
|
275
174
|
slice(*self.class.always_permitted_parameters).permit!.to_h
|
276
175
|
end
|
277
176
|
end
|
278
177
|
|
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
178
|
# Returns an unsafe, unfiltered
|
339
|
-
# <tt>ActiveSupport::HashWithIndifferentAccess</tt> representation of
|
340
|
-
#
|
179
|
+
# <tt>ActiveSupport::HashWithIndifferentAccess</tt> representation of this
|
180
|
+
# parameter.
|
341
181
|
#
|
342
182
|
# params = ActionController::Parameters.new({
|
343
|
-
# name:
|
344
|
-
# oddity:
|
183
|
+
# name: 'Senjougahara Hitagi',
|
184
|
+
# oddity: 'Heavy stone crab'
|
345
185
|
# })
|
346
186
|
# params.to_unsafe_h
|
347
187
|
# # => {"name"=>"Senjougahara Hitagi", "oddity" => "Heavy stone crab"}
|
@@ -386,7 +226,7 @@ module ActionController
|
|
386
226
|
# class Person < ActiveRecord::Base
|
387
227
|
# end
|
388
228
|
#
|
389
|
-
# params = ActionController::Parameters.new(name:
|
229
|
+
# params = ActionController::Parameters.new(name: 'Francesco')
|
390
230
|
# params.permitted? # => false
|
391
231
|
# Person.new(params) # => ActiveModel::ForbiddenAttributesError
|
392
232
|
# params.permit!
|
@@ -408,7 +248,7 @@ module ActionController
|
|
408
248
|
# When passed a single key, if it exists and its associated value is
|
409
249
|
# either present or the singleton +false+, returns said value:
|
410
250
|
#
|
411
|
-
# ActionController::Parameters.new(person: { name:
|
251
|
+
# ActionController::Parameters.new(person: { name: 'Francesco' }).require(:person)
|
412
252
|
# # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
413
253
|
#
|
414
254
|
# Otherwise raises <tt>ActionController::ParameterMissing</tt>:
|
@@ -441,7 +281,7 @@ module ActionController
|
|
441
281
|
# Technically this method can be used to fetch terminal values:
|
442
282
|
#
|
443
283
|
# # CAREFUL
|
444
|
-
# params = ActionController::Parameters.new(person: { name:
|
284
|
+
# params = ActionController::Parameters.new(person: { name: 'Finn' })
|
445
285
|
# name = params.require(:person).require(:name) # CAREFUL
|
446
286
|
#
|
447
287
|
# but take into account that at some point those ones have to be permitted:
|
@@ -471,7 +311,7 @@ module ActionController
|
|
471
311
|
# for the object to +true+. This is useful for limiting which attributes
|
472
312
|
# should be allowed for mass updating.
|
473
313
|
#
|
474
|
-
# params = ActionController::Parameters.new(user: { name:
|
314
|
+
# params = ActionController::Parameters.new(user: { name: 'Francesco', age: 22, role: 'admin' })
|
475
315
|
# permitted = params.require(:user).permit(:name, :age)
|
476
316
|
# permitted.permitted? # => true
|
477
317
|
# permitted.has_key?(:name) # => true
|
@@ -491,18 +331,27 @@ module ActionController
|
|
491
331
|
# You may declare that the parameter should be an array of permitted scalars
|
492
332
|
# by mapping it to an empty array:
|
493
333
|
#
|
494
|
-
# params = ActionController::Parameters.new(tags: [
|
334
|
+
# params = ActionController::Parameters.new(tags: ['rails', 'parameters'])
|
495
335
|
# params.permit(tags: [])
|
496
336
|
#
|
337
|
+
# Sometimes it is not possible or convenient to declare the valid keys of
|
338
|
+
# a hash parameter or its internal structure. Just map to an empty hash:
|
339
|
+
#
|
340
|
+
# params.permit(preferences: {})
|
341
|
+
#
|
342
|
+
# but be careful because this opens the door to arbitrary input. In this
|
343
|
+
# case, +permit+ ensures values in the returned structure are permitted
|
344
|
+
# scalars and filters out anything else.
|
345
|
+
#
|
497
346
|
# You can also use +permit+ on nested parameters, like:
|
498
347
|
#
|
499
348
|
# params = ActionController::Parameters.new({
|
500
349
|
# person: {
|
501
|
-
# name:
|
350
|
+
# name: 'Francesco',
|
502
351
|
# age: 22,
|
503
352
|
# pets: [{
|
504
|
-
# name:
|
505
|
-
# category:
|
353
|
+
# name: 'Purplish',
|
354
|
+
# category: 'dogs'
|
506
355
|
# }]
|
507
356
|
# }
|
508
357
|
# })
|
@@ -521,8 +370,8 @@ module ActionController
|
|
521
370
|
# params = ActionController::Parameters.new({
|
522
371
|
# person: {
|
523
372
|
# contact: {
|
524
|
-
# email:
|
525
|
-
# phone:
|
373
|
+
# email: 'none@test.com',
|
374
|
+
# phone: '555-1234'
|
526
375
|
# }
|
527
376
|
# }
|
528
377
|
# })
|
@@ -542,7 +391,7 @@ module ActionController
|
|
542
391
|
case filter
|
543
392
|
when Symbol, String
|
544
393
|
permitted_scalar_filter(params, filter)
|
545
|
-
when Hash
|
394
|
+
when Hash
|
546
395
|
hash_filter(params, filter)
|
547
396
|
end
|
548
397
|
end
|
@@ -555,7 +404,7 @@ module ActionController
|
|
555
404
|
# Returns a parameter for the given +key+. If not found,
|
556
405
|
# returns +nil+.
|
557
406
|
#
|
558
|
-
# params = ActionController::Parameters.new(person: { name:
|
407
|
+
# params = ActionController::Parameters.new(person: { name: 'Francesco' })
|
559
408
|
# params[:person] # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
560
409
|
# params[:none] # => nil
|
561
410
|
def [](key)
|
@@ -574,11 +423,11 @@ module ActionController
|
|
574
423
|
# if more arguments are given, then that will be returned; if a block
|
575
424
|
# is given, then that will be run and its result returned.
|
576
425
|
#
|
577
|
-
# params = ActionController::Parameters.new(person: { name:
|
426
|
+
# params = ActionController::Parameters.new(person: { name: 'Francesco' })
|
578
427
|
# params.fetch(:person) # => <ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
579
428
|
# params.fetch(:none) # => ActionController::ParameterMissing: param is missing or the value is empty: none
|
580
|
-
# params.fetch(:none,
|
581
|
-
# params.fetch(:none) {
|
429
|
+
# params.fetch(:none, 'Francesco') # => "Francesco"
|
430
|
+
# params.fetch(:none) { 'Francesco' } # => "Francesco"
|
582
431
|
def fetch(key, *args)
|
583
432
|
convert_value_to_parameters(
|
584
433
|
@parameters.fetch(key) {
|
@@ -595,12 +444,12 @@ module ActionController
|
|
595
444
|
# Extracts the nested parameter from the given +keys+ by calling +dig+
|
596
445
|
# at each step. Returns +nil+ if any intermediate step is +nil+.
|
597
446
|
#
|
598
|
-
#
|
599
|
-
#
|
600
|
-
#
|
447
|
+
# params = ActionController::Parameters.new(foo: { bar: { baz: 1 } })
|
448
|
+
# params.dig(:foo, :bar, :baz) # => 1
|
449
|
+
# params.dig(:foo, :zot, :xyz) # => nil
|
601
450
|
#
|
602
|
-
#
|
603
|
-
#
|
451
|
+
# params2 = ActionController::Parameters.new(foo: [10, 11, 12])
|
452
|
+
# params2.dig(:foo, 1) # => 11
|
604
453
|
def dig(*keys)
|
605
454
|
convert_value_to_parameters(@parameters.dig(*keys))
|
606
455
|
end
|
@@ -689,8 +538,8 @@ module ActionController
|
|
689
538
|
# to key. If the key is not found, returns the default value. If the
|
690
539
|
# optional code block is given and the key is not found, pass in the key
|
691
540
|
# and return the result of block.
|
692
|
-
def delete(key
|
693
|
-
convert_value_to_parameters(@parameters.delete(key
|
541
|
+
def delete(key)
|
542
|
+
convert_value_to_parameters(@parameters.delete(key))
|
694
543
|
end
|
695
544
|
|
696
545
|
# Returns a new instance of <tt>ActionController::Parameters</tt> with only
|
@@ -699,7 +548,7 @@ module ActionController
|
|
699
548
|
new_instance_with_inherited_permitted_status(@parameters.select(&block))
|
700
549
|
end
|
701
550
|
|
702
|
-
# Equivalent to Hash#keep_if, but returns nil if no changes were made.
|
551
|
+
# Equivalent to Hash#keep_if, but returns +nil+ if no changes were made.
|
703
552
|
def select!(&block)
|
704
553
|
@parameters.select!(&block)
|
705
554
|
self
|
@@ -755,52 +604,32 @@ module ActionController
|
|
755
604
|
# Wire up YAML format compatibility with Rails 4.2 and Psych 2.0.8 and 2.0.9+.
|
756
605
|
# Makes the YAML parser call `init_with` when it encounters the keys below
|
757
606
|
# instead of trying its own parsing routines.
|
758
|
-
YAML.load_tags[
|
759
|
-
YAML.load_tags[
|
607
|
+
YAML.load_tags["!ruby/hash-with-ivars:ActionController::Parameters"] = name
|
608
|
+
YAML.load_tags["!ruby/hash:ActionController::Parameters"] = name
|
760
609
|
end
|
761
610
|
hook_into_yaml_loading
|
762
611
|
|
763
612
|
def init_with(coder) # :nodoc:
|
764
613
|
case coder.tag
|
765
|
-
when
|
614
|
+
when "!ruby/hash:ActionController::Parameters"
|
766
615
|
# YAML 2.0.8's format where hash instance variables weren't stored.
|
767
616
|
@parameters = coder.map.with_indifferent_access
|
768
617
|
@permitted = false
|
769
|
-
when
|
618
|
+
when "!ruby/hash-with-ivars:ActionController::Parameters"
|
770
619
|
# YAML 2.0.9's Hash subclass format where keys and values
|
771
620
|
# were stored under an elements hash and `permitted` within an ivars hash.
|
772
|
-
@parameters = coder.map[
|
773
|
-
@permitted = coder.map[
|
774
|
-
when
|
621
|
+
@parameters = coder.map["elements"].with_indifferent_access
|
622
|
+
@permitted = coder.map["ivars"][:@permitted]
|
623
|
+
when "!ruby/object:ActionController::Parameters"
|
775
624
|
# YAML's Object format. Only needed because of the format
|
776
625
|
# backwardscompability above, otherwise equivalent to YAML's initialization.
|
777
|
-
@parameters, @permitted = coder.map[
|
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
|
626
|
+
@parameters, @permitted = coder.map["parameters"], coder.map["permitted"]
|
796
627
|
end
|
797
628
|
end
|
798
629
|
|
799
|
-
|
800
|
-
super || @parameters.respond_to?(name, include_all)
|
801
|
-
end
|
630
|
+
undef_method :to_param
|
802
631
|
|
803
|
-
# Returns duplicate of object including all parameters
|
632
|
+
# Returns duplicate of object including all parameters
|
804
633
|
def deep_dup
|
805
634
|
self.class.new(@parameters.deep_dup).tap do |duplicate|
|
806
635
|
duplicate.permitted = @permitted
|
@@ -867,7 +696,7 @@ module ActionController
|
|
867
696
|
when Parameters
|
868
697
|
if object.fields_for_style?
|
869
698
|
hash = object.class.new
|
870
|
-
object.each { |k,v| hash[k] = yield v }
|
699
|
+
object.each { |k, v| hash[k] = yield v }
|
871
700
|
hash
|
872
701
|
else
|
873
702
|
yield object
|
@@ -889,7 +718,7 @@ module ActionController
|
|
889
718
|
end
|
890
719
|
|
891
720
|
def unpermitted_keys(params)
|
892
|
-
|
721
|
+
keys - params.keys - always_permitted_parameters
|
893
722
|
end
|
894
723
|
|
895
724
|
#
|
@@ -920,7 +749,7 @@ module ActionController
|
|
920
749
|
]
|
921
750
|
|
922
751
|
def permitted_scalar?(value)
|
923
|
-
PERMITTED_SCALAR_TYPES.any? {|type| value.is_a?(type)}
|
752
|
+
PERMITTED_SCALAR_TYPES.any? { |type| value.is_a?(type) }
|
924
753
|
end
|
925
754
|
|
926
755
|
def permitted_scalar_filter(params, key)
|
@@ -936,7 +765,7 @@ module ActionController
|
|
936
765
|
end
|
937
766
|
|
938
767
|
def array_of_permitted_scalars?(value)
|
939
|
-
if value.is_a?(Array) && value.all? {|element| permitted_scalar?(element)}
|
768
|
+
if value.is_a?(Array) && value.all? { |element| permitted_scalar?(element) }
|
940
769
|
yield value
|
941
770
|
end
|
942
771
|
end
|
@@ -946,6 +775,7 @@ module ActionController
|
|
946
775
|
end
|
947
776
|
|
948
777
|
EMPTY_ARRAY = []
|
778
|
+
EMPTY_HASH = {}
|
949
779
|
def hash_filter(params, filter)
|
950
780
|
filter = filter.with_indifferent_access
|
951
781
|
|
@@ -959,6 +789,11 @@ module ActionController
|
|
959
789
|
array_of_permitted_scalars?(self[key]) do |val|
|
960
790
|
params[key] = val
|
961
791
|
end
|
792
|
+
elsif filter[key] == EMPTY_HASH
|
793
|
+
# Declaration { preferences: {} }.
|
794
|
+
if value.is_a?(Parameters)
|
795
|
+
params[key] = permit_any_in_parameters(value)
|
796
|
+
end
|
962
797
|
elsif non_scalar?(value)
|
963
798
|
# Declaration { user: :name } or { user: [:name, :age, { address: ... }] }.
|
964
799
|
params[key] = each_element(value) do |element|
|
@@ -968,6 +803,38 @@ module ActionController
|
|
968
803
|
end
|
969
804
|
end
|
970
805
|
|
806
|
+
def permit_any_in_parameters(params)
|
807
|
+
self.class.new.tap do |sanitized|
|
808
|
+
params.each do |key, value|
|
809
|
+
case value
|
810
|
+
when ->(v) { permitted_scalar?(v) }
|
811
|
+
sanitized[key] = value
|
812
|
+
when Array
|
813
|
+
sanitized[key] = permit_any_in_array(value)
|
814
|
+
when Parameters
|
815
|
+
sanitized[key] = permit_any_in_parameters(value)
|
816
|
+
else
|
817
|
+
# Filter this one out.
|
818
|
+
end
|
819
|
+
end
|
820
|
+
end
|
821
|
+
end
|
822
|
+
|
823
|
+
def permit_any_in_array(array)
|
824
|
+
[].tap do |sanitized|
|
825
|
+
array.each do |element|
|
826
|
+
case element
|
827
|
+
when ->(e) { permitted_scalar?(e) }
|
828
|
+
sanitized << element
|
829
|
+
when Parameters
|
830
|
+
sanitized << permit_any_in_parameters(element)
|
831
|
+
else
|
832
|
+
# Filter this one out.
|
833
|
+
end
|
834
|
+
end
|
835
|
+
end
|
836
|
+
end
|
837
|
+
|
971
838
|
def initialize_copy(source)
|
972
839
|
super
|
973
840
|
@parameters = @parameters.dup
|
@@ -987,7 +854,7 @@ module ActionController
|
|
987
854
|
#
|
988
855
|
# class PeopleController < ActionController::Base
|
989
856
|
# # Using "Person.create(params[:person])" would raise an
|
990
|
-
# # ActiveModel::
|
857
|
+
# # ActiveModel::ForbiddenAttributesError exception because it'd
|
991
858
|
# # be using mass assignment without an explicit permit step.
|
992
859
|
# # This is the recommended form:
|
993
860
|
# def create
|