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.

Files changed (128) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +189 -1002
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/abstract_controller.rb +3 -3
  6. data/lib/abstract_controller/base.rb +10 -12
  7. data/lib/abstract_controller/caching.rb +6 -3
  8. data/lib/abstract_controller/caching/fragments.rb +1 -1
  9. data/lib/abstract_controller/callbacks.rb +2 -43
  10. data/lib/abstract_controller/collector.rb +2 -2
  11. data/lib/abstract_controller/helpers.rb +19 -19
  12. data/lib/abstract_controller/rendering.rb +9 -11
  13. data/lib/abstract_controller/translation.rb +3 -3
  14. data/lib/action_controller.rb +15 -13
  15. data/lib/action_controller/api.rb +3 -3
  16. data/lib/action_controller/base.rb +7 -12
  17. data/lib/action_controller/caching.rb +1 -1
  18. data/lib/action_controller/log_subscriber.rb +2 -2
  19. data/lib/action_controller/metal.rb +34 -43
  20. data/lib/action_controller/metal/conditional_get.rb +10 -9
  21. data/lib/action_controller/metal/data_streaming.rb +8 -9
  22. data/lib/action_controller/metal/etag_with_flash.rb +16 -0
  23. data/lib/action_controller/metal/etag_with_template_digest.rb +15 -15
  24. data/lib/action_controller/metal/exceptions.rb +4 -14
  25. data/lib/action_controller/metal/flash.rb +1 -1
  26. data/lib/action_controller/metal/force_ssl.rb +6 -6
  27. data/lib/action_controller/metal/head.rb +13 -19
  28. data/lib/action_controller/metal/helpers.rb +6 -6
  29. data/lib/action_controller/metal/http_authentication.rb +22 -23
  30. data/lib/action_controller/metal/implicit_render.rb +2 -5
  31. data/lib/action_controller/metal/instrumentation.rb +14 -14
  32. data/lib/action_controller/metal/live.rb +15 -16
  33. data/lib/action_controller/metal/mime_responds.rb +3 -3
  34. data/lib/action_controller/metal/parameter_encoding.rb +49 -0
  35. data/lib/action_controller/metal/params_wrapper.rb +32 -32
  36. data/lib/action_controller/metal/redirecting.rb +8 -24
  37. data/lib/action_controller/metal/renderers.rb +2 -3
  38. data/lib/action_controller/metal/rendering.rb +50 -60
  39. data/lib/action_controller/metal/request_forgery_protection.rb +51 -49
  40. data/lib/action_controller/metal/rescue.rb +1 -1
  41. data/lib/action_controller/metal/streaming.rb +4 -4
  42. data/lib/action_controller/metal/strong_parameters.rb +117 -250
  43. data/lib/action_controller/metal/testing.rb +1 -1
  44. data/lib/action_controller/metal/url_for.rb +4 -4
  45. data/lib/action_controller/railtie.rb +9 -13
  46. data/lib/action_controller/renderer.rb +17 -16
  47. data/lib/action_controller/test_case.rb +75 -148
  48. data/lib/action_dispatch.rb +20 -19
  49. data/lib/action_dispatch/http/cache.rb +9 -10
  50. data/lib/action_dispatch/http/filter_parameters.rb +8 -8
  51. data/lib/action_dispatch/http/filter_redirect.rb +2 -4
  52. data/lib/action_dispatch/http/headers.rb +10 -10
  53. data/lib/action_dispatch/http/mime_negotiation.rb +17 -22
  54. data/lib/action_dispatch/http/mime_type.rb +27 -52
  55. data/lib/action_dispatch/http/parameter_filter.rb +8 -6
  56. data/lib/action_dispatch/http/parameters.rb +40 -17
  57. data/lib/action_dispatch/http/request.rb +38 -34
  58. data/lib/action_dispatch/http/response.rb +16 -16
  59. data/lib/action_dispatch/http/upload.rb +6 -10
  60. data/lib/action_dispatch/http/url.rb +48 -74
  61. data/lib/action_dispatch/journey.rb +5 -5
  62. data/lib/action_dispatch/journey/formatter.rb +8 -4
  63. data/lib/action_dispatch/journey/gtg/builder.rb +5 -5
  64. data/lib/action_dispatch/journey/gtg/simulator.rb +1 -1
  65. data/lib/action_dispatch/journey/gtg/transition_table.rb +15 -15
  66. data/lib/action_dispatch/journey/nfa/builder.rb +3 -3
  67. data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
  68. data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
  69. data/lib/action_dispatch/journey/nfa/transition_table.rb +2 -2
  70. data/lib/action_dispatch/journey/nodes/node.rb +5 -5
  71. data/lib/action_dispatch/journey/parser.rb +23 -24
  72. data/lib/action_dispatch/journey/parser.y +3 -2
  73. data/lib/action_dispatch/journey/parser_extras.rb +2 -2
  74. data/lib/action_dispatch/journey/path/pattern.rb +10 -3
  75. data/lib/action_dispatch/journey/route.rb +19 -12
  76. data/lib/action_dispatch/journey/router.rb +19 -12
  77. data/lib/action_dispatch/journey/router/utils.rb +9 -9
  78. data/lib/action_dispatch/journey/scanner.rb +17 -15
  79. data/lib/action_dispatch/journey/visitors.rb +23 -23
  80. data/lib/action_dispatch/middleware/callbacks.rb +0 -12
  81. data/lib/action_dispatch/middleware/cookies.rb +39 -39
  82. data/lib/action_dispatch/middleware/debug_exceptions.rb +126 -112
  83. data/lib/action_dispatch/middleware/debug_locks.rb +8 -8
  84. data/lib/action_dispatch/middleware/exception_wrapper.rb +55 -55
  85. data/lib/action_dispatch/middleware/executor.rb +1 -1
  86. data/lib/action_dispatch/middleware/flash.rb +17 -16
  87. data/lib/action_dispatch/middleware/public_exceptions.rb +20 -20
  88. data/lib/action_dispatch/middleware/reloader.rb +3 -47
  89. data/lib/action_dispatch/middleware/remote_ip.rb +6 -8
  90. data/lib/action_dispatch/middleware/request_id.rb +6 -5
  91. data/lib/action_dispatch/middleware/session/abstract_store.rb +14 -26
  92. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  93. data/lib/action_dispatch/middleware/session/cookie_store.rb +35 -35
  94. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +2 -2
  95. data/lib/action_dispatch/middleware/show_exceptions.rb +19 -19
  96. data/lib/action_dispatch/middleware/ssl.rb +9 -27
  97. data/lib/action_dispatch/middleware/stack.rb +7 -26
  98. data/lib/action_dispatch/middleware/static.rb +13 -24
  99. data/lib/action_dispatch/railtie.rb +9 -11
  100. data/lib/action_dispatch/request/session.rb +22 -22
  101. data/lib/action_dispatch/request/utils.rb +11 -2
  102. data/lib/action_dispatch/routing.rb +8 -6
  103. data/lib/action_dispatch/routing/inspector.rb +37 -37
  104. data/lib/action_dispatch/routing/mapper.rb +296 -203
  105. data/lib/action_dispatch/routing/polymorphic_routes.rb +160 -134
  106. data/lib/action_dispatch/routing/redirection.rb +27 -22
  107. data/lib/action_dispatch/routing/route_set.rb +206 -92
  108. data/lib/action_dispatch/routing/routes_proxy.rb +2 -2
  109. data/lib/action_dispatch/routing/url_for.rb +14 -12
  110. data/lib/action_dispatch/system_test_case.rb +119 -0
  111. data/lib/action_dispatch/system_testing/browser.rb +28 -0
  112. data/lib/action_dispatch/system_testing/driver.rb +18 -0
  113. data/lib/action_dispatch/system_testing/server.rb +32 -0
  114. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +61 -0
  115. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +20 -0
  116. data/lib/action_dispatch/testing/assertion_response.rb +6 -6
  117. data/lib/action_dispatch/testing/assertions.rb +4 -4
  118. data/lib/action_dispatch/testing/assertions/response.rb +8 -3
  119. data/lib/action_dispatch/testing/assertions/routing.rb +11 -11
  120. data/lib/action_dispatch/testing/integration.rb +47 -138
  121. data/lib/action_dispatch/testing/test_process.rb +2 -2
  122. data/lib/action_dispatch/testing/test_request.rb +16 -16
  123. data/lib/action_dispatch/testing/test_response.rb +1 -1
  124. data/lib/action_pack.rb +2 -2
  125. data/lib/action_pack/gem_version.rb +3 -3
  126. data/lib/action_pack/version.rb +1 -1
  127. metadata +20 -12
  128. 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['action_dispatch.show_detailed_exceptions'] ||= show_detailed_exceptions?
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 'rack/chunked'
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
- protected
196
+ private
197
197
 
198
198
  # Set proper cache control and transfer encoding when streaming
199
- def _process_options(options) #:nodoc:
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) #:nodoc:
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 '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'
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: "Francesco",
56
+ # name: 'Francesco',
69
57
  # age: 22,
70
- # role: "admin"
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 <tt>:log</tt> to
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: "value")
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
- 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.
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, :to_s, to: :@parameters
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: "Francesco")
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: "Francesco")
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
- 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
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 the parameters with all unpermitted keys removed.
160
+ # representation of this parameter with all unpermitted keys removed.
259
161
  #
260
162
  # params = ActionController::Parameters.new({
261
- # name: "Senjougahara Hitagi",
262
- # oddity: "Heavy stone crab"
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 the
340
- # parameters.
179
+ # <tt>ActiveSupport::HashWithIndifferentAccess</tt> representation of this
180
+ # parameter.
341
181
  #
342
182
  # params = ActionController::Parameters.new({
343
- # name: "Senjougahara Hitagi",
344
- # oddity: "Heavy stone crab"
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: "Francesco")
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: "Francesco" }).require(:person)
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: "Finn" })
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: "Francesco", age: 22, role: "admin" })
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: ["rails", "parameters"])
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: "Francesco",
350
+ # name: 'Francesco',
502
351
  # age: 22,
503
352
  # pets: [{
504
- # name: "Purplish",
505
- # category: "dogs"
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: "none@test.com",
525
- # phone: "555-1234"
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 then
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: "Francesco" })
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: "Francesco" })
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, "Francesco") # => "Francesco"
581
- # params.fetch(:none) { "Francesco" } # => "Francesco"
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
- # params = ActionController::Parameters.new(foo: { bar: { baz: 1 } })
599
- # params.dig(:foo, :bar, :baz) # => 1
600
- # params.dig(:foo, :zot, :xyz) # => nil
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
- # params2 = ActionController::Parameters.new(foo: [10, 11, 12])
603
- # params2.dig(:foo, 1) # => 11
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, &block)
693
- convert_value_to_parameters(@parameters.delete(key, &block))
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['!ruby/hash-with-ivars:ActionController::Parameters'] = name
759
- YAML.load_tags['!ruby/hash:ActionController::Parameters'] = name
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 '!ruby/hash:ActionController::Parameters'
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 '!ruby/hash-with-ivars:ActionController::Parameters'
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['elements'].with_indifferent_access
773
- @permitted = coder.map['ivars'][:@permitted]
774
- when '!ruby/object:ActionController::Parameters'
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['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
626
+ @parameters, @permitted = coder.map["parameters"], coder.map["permitted"]
796
627
  end
797
628
  end
798
629
 
799
- def respond_to?(name, include_all = false) # :nodoc:
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
- self.keys - params.keys - self.always_permitted_parameters
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::ForbiddenAttributes exception because it'd
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