actionpack 4.2.10 → 5.0.0
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 +553 -401
- 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 +52 -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 +10 -13
- 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 +11 -32
- data/lib/action_controller/metal/etag_with_template_digest.rb +1 -1
- data/lib/action_controller/metal/exceptions.rb +11 -6
- data/lib/action_controller/metal/force_ssl.rb +10 -10
- 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 +66 -88
- data/lib/action_controller/metal/mime_responds.rb +27 -42
- data/lib/action_controller/metal/params_wrapper.rb +8 -8
- data/lib/action_controller/metal/redirecting.rb +32 -9
- data/lib/action_controller/metal/renderers.rb +85 -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 +293 -90
- 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/renderer.rb +111 -0
- data/lib/action_controller/template_assertions.rb +9 -0
- data/lib/action_controller/test_case.rb +288 -368
- data/lib/action_controller.rb +12 -9
- data/lib/action_dispatch/http/cache.rb +73 -34
- data/lib/action_dispatch/http/filter_parameters.rb +15 -11
- data/lib/action_dispatch/http/filter_redirect.rb +7 -8
- data/lib/action_dispatch/http/headers.rb +44 -13
- data/lib/action_dispatch/http/mime_negotiation.rb +41 -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 +18 -8
- data/lib/action_dispatch/http/parameters.rb +54 -41
- data/lib/action_dispatch/http/request.rb +149 -82
- data/lib/action_dispatch/http/response.rb +206 -102
- data/lib/action_dispatch/http/url.rb +117 -8
- data/lib/action_dispatch/journey/formatter.rb +39 -28
- 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_extras.rb +4 -0
- data/lib/action_dispatch/journey/path/pattern.rb +38 -42
- data/lib/action_dispatch/journey/route.rb +74 -19
- data/lib/action_dispatch/journey/router/utils.rb +5 -5
- data/lib/action_dispatch/journey/router.rb +5 -9
- data/lib/action_dispatch/journey/routes.rb +14 -15
- data/lib/action_dispatch/journey/visitors.rb +86 -43
- data/lib/action_dispatch/middleware/callbacks.rb +10 -1
- data/lib/action_dispatch/middleware/cookies.rb +189 -135
- data/lib/action_dispatch/middleware/debug_exceptions.rb +124 -49
- 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 +115 -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 +491 -338
- data/lib/action_dispatch/routing/polymorphic_routes.rb +8 -14
- data/lib/action_dispatch/routing/redirection.rb +3 -3
- data/lib/action_dispatch/routing/route_set.rb +145 -238
- 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 +11 -10
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/integration.rb +368 -97
- data/lib/action_dispatch/testing/test_process.rb +5 -6
- data/lib/action_dispatch/testing/test_request.rb +22 -31
- data/lib/action_dispatch/testing/test_response.rb +7 -4
- data/lib/action_dispatch.rb +3 -1
- data/lib/action_pack/gem_version.rb +3 -3
- data/lib/action_pack.rb +1 -1
- metadata +30 -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,9 +1,10 @@
|
|
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/deprecation'
|
5
5
|
require 'active_support/rescuable'
|
6
6
|
require 'action_dispatch/http/upload'
|
7
|
+
require 'rack/test'
|
7
8
|
require 'stringio'
|
8
9
|
require 'set'
|
9
10
|
|
@@ -12,9 +13,9 @@ module ActionController
|
|
12
13
|
#
|
13
14
|
# params = ActionController::Parameters.new(a: {})
|
14
15
|
# params.fetch(:b)
|
15
|
-
# # => ActionController::ParameterMissing: param
|
16
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty: b
|
16
17
|
# params.require(:a)
|
17
|
-
# # => ActionController::ParameterMissing: param
|
18
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty: a
|
18
19
|
class ParameterMissing < KeyError
|
19
20
|
attr_reader :param # :nodoc:
|
20
21
|
|
@@ -42,7 +43,7 @@ module ActionController
|
|
42
43
|
|
43
44
|
# == Action Controller \Parameters
|
44
45
|
#
|
45
|
-
# Allows to choose which attributes should be whitelisted for mass updating
|
46
|
+
# Allows you to choose which attributes should be whitelisted for mass updating
|
46
47
|
# and thus prevent accidentally exposing that which shouldn't be exposed.
|
47
48
|
# Provides two methods for this purpose: #require and #permit. The former is
|
48
49
|
# used to mark parameters as required. The latter is used to set the parameter
|
@@ -98,17 +99,19 @@ module ActionController
|
|
98
99
|
# environment they should only be set once at boot-time and never mutated at
|
99
100
|
# runtime.
|
100
101
|
#
|
101
|
-
# <tt>ActionController::Parameters</tt>
|
102
|
-
# <tt
|
103
|
-
# that you can fetch values using either <tt>:key</tt> or <tt>"key"</tt>.
|
102
|
+
# You can fetch values of <tt>ActionController::Parameters</tt> using either
|
103
|
+
# <tt>:key</tt> or <tt>"key"</tt>.
|
104
104
|
#
|
105
105
|
# params = ActionController::Parameters.new(key: 'value')
|
106
106
|
# params[:key] # => "value"
|
107
107
|
# params["key"] # => "value"
|
108
|
-
class Parameters
|
108
|
+
class Parameters
|
109
109
|
cattr_accessor :permit_all_parameters, instance_accessor: false
|
110
110
|
cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
|
111
111
|
|
112
|
+
delegate :keys, :key?, :has_key?, :values, :has_value?, :value?, :empty?, :include?,
|
113
|
+
:as_json, to: :@parameters
|
114
|
+
|
112
115
|
# By default, never raise an UnpermittedParameters exception if these
|
113
116
|
# params are present. The default includes both 'controller' and 'action'
|
114
117
|
# because they are added by Rails and should be of no concern. One way
|
@@ -119,16 +122,6 @@ module ActionController
|
|
119
122
|
cattr_accessor :always_permitted_parameters
|
120
123
|
self.always_permitted_parameters = %w( controller action )
|
121
124
|
|
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
125
|
# Returns a new instance of <tt>ActionController::Parameters</tt>.
|
133
126
|
# Also, sets the +permitted+ attribute to the default value of
|
134
127
|
# <tt>ActionController::Parameters.permit_all_parameters</tt>.
|
@@ -145,13 +138,32 @@ module ActionController
|
|
145
138
|
# params = ActionController::Parameters.new(name: 'Francesco')
|
146
139
|
# params.permitted? # => true
|
147
140
|
# Person.new(params) # => #<Person id: nil, name: "Francesco">
|
148
|
-
def initialize(
|
149
|
-
|
141
|
+
def initialize(parameters = {})
|
142
|
+
@parameters = parameters.with_indifferent_access
|
150
143
|
@permitted = self.class.permit_all_parameters
|
151
144
|
end
|
152
145
|
|
153
|
-
# Returns
|
154
|
-
#
|
146
|
+
# Returns true if another +Parameters+ object contains the same content and
|
147
|
+
# permitted flag.
|
148
|
+
def ==(other)
|
149
|
+
if other.respond_to?(:permitted?)
|
150
|
+
self.permitted? == other.permitted? && self.parameters == other.parameters
|
151
|
+
elsif other.is_a?(Hash)
|
152
|
+
ActiveSupport::Deprecation.warn <<-WARNING.squish
|
153
|
+
Comparing equality between `ActionController::Parameters` and a
|
154
|
+
`Hash` is deprecated and will be removed in Rails 5.1. Please only do
|
155
|
+
comparisons between instances of `ActionController::Parameters`. If
|
156
|
+
you need to compare to a hash, first convert it using
|
157
|
+
`ActionController::Parameters#new`.
|
158
|
+
WARNING
|
159
|
+
@parameters == other.with_indifferent_access
|
160
|
+
else
|
161
|
+
@parameters == other
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Returns a safe <tt>ActiveSupport::HashWithIndifferentAccess</tt>
|
166
|
+
# representation of this parameter with all unpermitted keys removed.
|
155
167
|
#
|
156
168
|
# params = ActionController::Parameters.new({
|
157
169
|
# name: 'Senjougahara Hitagi',
|
@@ -163,28 +175,34 @@ module ActionController
|
|
163
175
|
# safe_params.to_h # => {"name"=>"Senjougahara Hitagi"}
|
164
176
|
def to_h
|
165
177
|
if permitted?
|
166
|
-
|
178
|
+
convert_parameters_to_hashes(@parameters, :to_h)
|
167
179
|
else
|
168
180
|
slice(*self.class.always_permitted_parameters).permit!.to_h
|
169
181
|
end
|
170
182
|
end
|
171
183
|
|
172
|
-
# Returns an unsafe, unfiltered
|
184
|
+
# Returns an unsafe, unfiltered
|
185
|
+
# <tt>ActiveSupport::HashWithIndifferentAccess</tt> representation of this
|
186
|
+
# parameter.
|
187
|
+
#
|
188
|
+
# params = ActionController::Parameters.new({
|
189
|
+
# name: 'Senjougahara Hitagi',
|
190
|
+
# oddity: 'Heavy stone crab'
|
191
|
+
# })
|
192
|
+
# params.to_unsafe_h
|
193
|
+
# # => {"name"=>"Senjougahara Hitagi", "oddity" => "Heavy stone crab"}
|
173
194
|
def to_unsafe_h
|
174
|
-
|
195
|
+
convert_parameters_to_hashes(@parameters, :to_unsafe_h)
|
175
196
|
end
|
176
197
|
alias_method :to_unsafe_hash, :to_unsafe_h
|
177
198
|
|
178
|
-
# Convert all hashes in values into parameters, then yield each pair
|
199
|
+
# Convert all hashes in values into parameters, then yield each pair in
|
179
200
|
# the same way as <tt>Hash#each_pair</tt>
|
180
201
|
def each_pair(&block)
|
181
|
-
|
182
|
-
convert_hashes_to_parameters(key, value)
|
202
|
+
@parameters.each_pair do |key, value|
|
203
|
+
yield key, convert_hashes_to_parameters(key, value)
|
183
204
|
end
|
184
|
-
|
185
|
-
super
|
186
205
|
end
|
187
|
-
|
188
206
|
alias_method :each, :each_pair
|
189
207
|
|
190
208
|
# Attribute that keeps track of converted arrays, if any, to avoid double
|
@@ -231,19 +249,58 @@ module ActionController
|
|
231
249
|
self
|
232
250
|
end
|
233
251
|
|
234
|
-
#
|
235
|
-
#
|
236
|
-
#
|
252
|
+
# This method accepts both a single key and an array of keys.
|
253
|
+
#
|
254
|
+
# When passed a single key, if it exists and its associated value is
|
255
|
+
# either present or the singleton +false+, returns said value:
|
237
256
|
#
|
238
257
|
# ActionController::Parameters.new(person: { name: 'Francesco' }).require(:person)
|
239
258
|
# # => {"name"=>"Francesco"}
|
240
259
|
#
|
260
|
+
# Otherwise raises <tt>ActionController::ParameterMissing</tt>:
|
261
|
+
#
|
262
|
+
# ActionController::Parameters.new.require(:person)
|
263
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty: person
|
264
|
+
#
|
241
265
|
# ActionController::Parameters.new(person: nil).require(:person)
|
242
|
-
# #
|
266
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty: person
|
267
|
+
#
|
268
|
+
# ActionController::Parameters.new(person: "\t").require(:person)
|
269
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty: person
|
243
270
|
#
|
244
271
|
# ActionController::Parameters.new(person: {}).require(:person)
|
245
|
-
# #
|
272
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty: person
|
273
|
+
#
|
274
|
+
# When given an array of keys, the method tries to require each one of them
|
275
|
+
# in order. If it succeeds, an array with the respective return values is
|
276
|
+
# returned:
|
277
|
+
#
|
278
|
+
# params = ActionController::Parameters.new(user: { ... }, profile: { ... })
|
279
|
+
# user_params, profile_params = params.require(:user, :profile)
|
280
|
+
#
|
281
|
+
# Otherwise, the method re-raises the first exception found:
|
282
|
+
#
|
283
|
+
# params = ActionController::Parameters.new(user: {}, profile: {})
|
284
|
+
# user_params, profile_params = params.require(:user, :profile)
|
285
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty: user
|
286
|
+
#
|
287
|
+
# Technically this method can be used to fetch terminal values:
|
288
|
+
#
|
289
|
+
# # CAREFUL
|
290
|
+
# params = ActionController::Parameters.new(person: { name: 'Finn' })
|
291
|
+
# name = params.require(:person).require(:name) # CAREFUL
|
292
|
+
#
|
293
|
+
# but take into account that at some point those ones have to be permitted:
|
294
|
+
#
|
295
|
+
# def person_params
|
296
|
+
# params.require(:person).permit(:name).tap do |person_params|
|
297
|
+
# person_params.require(:name) # SAFER
|
298
|
+
# end
|
299
|
+
# end
|
300
|
+
#
|
301
|
+
# for example.
|
246
302
|
def require(key)
|
303
|
+
return key.map { |k| require(k) } if key.is_a?(Array)
|
247
304
|
value = self[key]
|
248
305
|
if value.present? || value == false
|
249
306
|
value
|
@@ -271,7 +328,7 @@ module ActionController
|
|
271
328
|
#
|
272
329
|
# params.permit(:name)
|
273
330
|
#
|
274
|
-
# +:name+ passes it is a key of +params+ whose associated value is of type
|
331
|
+
# +:name+ passes if it is a key of +params+ whose associated value is of type
|
275
332
|
# +String+, +Symbol+, +NilClass+, +Numeric+, +TrueClass+, +FalseClass+,
|
276
333
|
# +Date+, +Time+, +DateTime+, +StringIO+, +IO+,
|
277
334
|
# +ActionDispatch::Http::UploadedFile+ or +Rack::Test::UploadedFile+.
|
@@ -348,7 +405,13 @@ module ActionController
|
|
348
405
|
# params[:person] # => {"name"=>"Francesco"}
|
349
406
|
# params[:none] # => nil
|
350
407
|
def [](key)
|
351
|
-
convert_hashes_to_parameters(key,
|
408
|
+
convert_hashes_to_parameters(key, @parameters[key])
|
409
|
+
end
|
410
|
+
|
411
|
+
# Assigns a value to a given +key+. The given key may still get filtered out
|
412
|
+
# when +permit+ is called.
|
413
|
+
def []=(key, value)
|
414
|
+
@parameters[key] = value
|
352
415
|
end
|
353
416
|
|
354
417
|
# Returns a parameter for the given +key+. If the +key+
|
@@ -359,13 +422,34 @@ module ActionController
|
|
359
422
|
#
|
360
423
|
# params = ActionController::Parameters.new(person: { name: 'Francesco' })
|
361
424
|
# params.fetch(:person) # => {"name"=>"Francesco"}
|
362
|
-
# params.fetch(:none) # => ActionController::ParameterMissing: param
|
425
|
+
# params.fetch(:none) # => ActionController::ParameterMissing: param is missing or the value is empty: none
|
363
426
|
# params.fetch(:none, 'Francesco') # => "Francesco"
|
364
427
|
# params.fetch(:none) { 'Francesco' } # => "Francesco"
|
365
428
|
def fetch(key, *args)
|
366
|
-
|
367
|
-
|
368
|
-
|
429
|
+
convert_value_to_parameters(
|
430
|
+
@parameters.fetch(key) {
|
431
|
+
if block_given?
|
432
|
+
yield
|
433
|
+
else
|
434
|
+
args.fetch(0) { raise ActionController::ParameterMissing.new(key) }
|
435
|
+
end
|
436
|
+
}
|
437
|
+
)
|
438
|
+
end
|
439
|
+
|
440
|
+
if Hash.method_defined?(:dig)
|
441
|
+
# Extracts the nested parameter from the given +keys+ by calling +dig+
|
442
|
+
# at each step. Returns +nil+ if any intermediate step is +nil+.
|
443
|
+
#
|
444
|
+
# params = ActionController::Parameters.new(foo: { bar: { baz: 1 } })
|
445
|
+
# params.dig(:foo, :bar, :baz) # => 1
|
446
|
+
# params.dig(:foo, :zot, :xyz) # => nil
|
447
|
+
#
|
448
|
+
# params2 = ActionController::Parameters.new(foo: [10, 11, 12])
|
449
|
+
# params2.dig(:foo, 1) # => 11
|
450
|
+
def dig(*keys)
|
451
|
+
convert_value_to_parameters(@parameters.dig(*keys))
|
452
|
+
end
|
369
453
|
end
|
370
454
|
|
371
455
|
# Returns a new <tt>ActionController::Parameters</tt> instance that
|
@@ -376,7 +460,24 @@ module ActionController
|
|
376
460
|
# params.slice(:a, :b) # => {"a"=>1, "b"=>2}
|
377
461
|
# params.slice(:d) # => {}
|
378
462
|
def slice(*keys)
|
379
|
-
new_instance_with_inherited_permitted_status(
|
463
|
+
new_instance_with_inherited_permitted_status(@parameters.slice(*keys))
|
464
|
+
end
|
465
|
+
|
466
|
+
# Returns current <tt>ActionController::Parameters</tt> instance which
|
467
|
+
# contains only the given +keys+.
|
468
|
+
def slice!(*keys)
|
469
|
+
@parameters.slice!(*keys)
|
470
|
+
self
|
471
|
+
end
|
472
|
+
|
473
|
+
# Returns a new <tt>ActionController::Parameters</tt> instance that
|
474
|
+
# filters out the given +keys+.
|
475
|
+
#
|
476
|
+
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
477
|
+
# params.except(:a, :b) # => {"c"=>3}
|
478
|
+
# params.except(:d) # => {"a"=>1,"b"=>2,"c"=>3}
|
479
|
+
def except(*keys)
|
480
|
+
new_instance_with_inherited_permitted_status(@parameters.except(*keys))
|
380
481
|
end
|
381
482
|
|
382
483
|
# Removes and returns the key/value pairs matching the given keys.
|
@@ -385,7 +486,7 @@ module ActionController
|
|
385
486
|
# params.extract!(:a, :b) # => {"a"=>1, "b"=>2}
|
386
487
|
# params # => {"c"=>3}
|
387
488
|
def extract!(*keys)
|
388
|
-
new_instance_with_inherited_permitted_status(
|
489
|
+
new_instance_with_inherited_permitted_status(@parameters.extract!(*keys))
|
389
490
|
end
|
390
491
|
|
391
492
|
# Returns a new <tt>ActionController::Parameters</tt> with the results of
|
@@ -394,36 +495,80 @@ module ActionController
|
|
394
495
|
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
395
496
|
# params.transform_values { |x| x * 2 }
|
396
497
|
# # => {"a"=>2, "b"=>4, "c"=>6}
|
397
|
-
def transform_values
|
398
|
-
if
|
399
|
-
new_instance_with_inherited_permitted_status(
|
498
|
+
def transform_values(&block)
|
499
|
+
if block
|
500
|
+
new_instance_with_inherited_permitted_status(
|
501
|
+
@parameters.transform_values(&block)
|
502
|
+
)
|
400
503
|
else
|
401
|
-
|
504
|
+
@parameters.transform_values
|
402
505
|
end
|
403
506
|
end
|
404
507
|
|
405
|
-
#
|
406
|
-
#
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
508
|
+
# Performs values transformation and returns the altered
|
509
|
+
# <tt>ActionController::Parameters</tt> instance.
|
510
|
+
def transform_values!(&block)
|
511
|
+
@parameters.transform_values!(&block)
|
512
|
+
self
|
513
|
+
end
|
514
|
+
|
515
|
+
# Returns a new <tt>ActionController::Parameters</tt> instance with the
|
516
|
+
# results of running +block+ once for every key. The values are unchanged.
|
517
|
+
def transform_keys(&block)
|
518
|
+
if block
|
519
|
+
new_instance_with_inherited_permitted_status(
|
520
|
+
@parameters.transform_keys(&block)
|
521
|
+
)
|
411
522
|
else
|
412
|
-
|
523
|
+
@parameters.transform_keys
|
413
524
|
end
|
414
525
|
end
|
415
526
|
|
527
|
+
# Performs keys transformation and returns the altered
|
528
|
+
# <tt>ActionController::Parameters</tt> instance.
|
529
|
+
def transform_keys!(&block)
|
530
|
+
@parameters.transform_keys!(&block)
|
531
|
+
self
|
532
|
+
end
|
533
|
+
|
416
534
|
# Deletes and returns a key-value pair from +Parameters+ whose key is equal
|
417
535
|
# to key. If the key is not found, returns the default value. If the
|
418
536
|
# optional code block is given and the key is not found, pass in the key
|
419
537
|
# and return the result of block.
|
420
|
-
def delete(key
|
421
|
-
|
538
|
+
def delete(key)
|
539
|
+
convert_value_to_parameters(@parameters.delete(key))
|
540
|
+
end
|
541
|
+
|
542
|
+
# Returns a new instance of <tt>ActionController::Parameters</tt> with only
|
543
|
+
# items that the block evaluates to true.
|
544
|
+
def select(&block)
|
545
|
+
new_instance_with_inherited_permitted_status(@parameters.select(&block))
|
422
546
|
end
|
423
547
|
|
424
548
|
# Equivalent to Hash#keep_if, but returns nil if no changes were made.
|
425
549
|
def select!(&block)
|
426
|
-
|
550
|
+
@parameters.select!(&block)
|
551
|
+
self
|
552
|
+
end
|
553
|
+
alias_method :keep_if, :select!
|
554
|
+
|
555
|
+
# Returns a new instance of <tt>ActionController::Parameters</tt> with items
|
556
|
+
# that the block evaluates to true removed.
|
557
|
+
def reject(&block)
|
558
|
+
new_instance_with_inherited_permitted_status(@parameters.reject(&block))
|
559
|
+
end
|
560
|
+
|
561
|
+
# Removes items that the block evaluates to true and returns self.
|
562
|
+
def reject!(&block)
|
563
|
+
@parameters.reject!(&block)
|
564
|
+
self
|
565
|
+
end
|
566
|
+
alias_method :delete_if, :reject!
|
567
|
+
|
568
|
+
# Returns values that were assigned to the given +keys+. Note that all the
|
569
|
+
# +Hash+ objects will be converted to <tt>ActionController::Parameters</tt>.
|
570
|
+
def values_at(*keys)
|
571
|
+
convert_value_to_parameters(@parameters.values_at(*keys))
|
427
572
|
end
|
428
573
|
|
429
574
|
# Returns an exact copy of the <tt>ActionController::Parameters</tt>
|
@@ -440,11 +585,54 @@ module ActionController
|
|
440
585
|
end
|
441
586
|
end
|
442
587
|
|
588
|
+
# Returns a new <tt>ActionController::Parameters</tt> with all keys from
|
589
|
+
# +other_hash+ merges into current hash.
|
590
|
+
def merge(other_hash)
|
591
|
+
new_instance_with_inherited_permitted_status(
|
592
|
+
@parameters.merge(other_hash)
|
593
|
+
)
|
594
|
+
end
|
595
|
+
|
596
|
+
# This is required by ActiveModel attribute assignment, so that user can
|
597
|
+
# pass +Parameters+ to a mass assignment methods in a model. It should not
|
598
|
+
# matter as we are using +HashWithIndifferentAccess+ internally.
|
599
|
+
def stringify_keys # :nodoc:
|
600
|
+
dup
|
601
|
+
end
|
602
|
+
|
603
|
+
def inspect
|
604
|
+
"<#{self.class} #{@parameters} permitted: #{@permitted}>"
|
605
|
+
end
|
606
|
+
|
607
|
+
def method_missing(method_sym, *args, &block)
|
608
|
+
if @parameters.respond_to?(method_sym)
|
609
|
+
message = <<-DEPRECATE.squish
|
610
|
+
Method #{method_sym} is deprecated and will be removed in Rails 5.1,
|
611
|
+
as `ActionController::Parameters` no longer inherits from
|
612
|
+
hash. Using this deprecated behavior exposes potential security
|
613
|
+
problems. If you continue to use this method you may be creating
|
614
|
+
a security vulnerability in your app that can be exploited. Instead,
|
615
|
+
consider using one of these documented methods which are not
|
616
|
+
deprecated: http://api.rubyonrails.org/v#{ActionPack.version}/classes/ActionController/Parameters.html
|
617
|
+
DEPRECATE
|
618
|
+
ActiveSupport::Deprecation.warn(message)
|
619
|
+
@parameters.public_send(method_sym, *args, &block)
|
620
|
+
else
|
621
|
+
super
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
443
625
|
protected
|
626
|
+
attr_reader :parameters
|
627
|
+
|
444
628
|
def permitted=(new_permitted)
|
445
629
|
@permitted = new_permitted
|
446
630
|
end
|
447
631
|
|
632
|
+
def fields_for_style?
|
633
|
+
@parameters.all? { |k, v| k =~ /\A-?\d+\z/ && (v.is_a?(Hash) || v.is_a?(Parameters)) }
|
634
|
+
end
|
635
|
+
|
448
636
|
private
|
449
637
|
def new_instance_with_inherited_permitted_status(hash)
|
450
638
|
self.class.new(hash).tap do |new_instance|
|
@@ -452,40 +640,56 @@ module ActionController
|
|
452
640
|
end
|
453
641
|
end
|
454
642
|
|
455
|
-
def
|
643
|
+
def convert_parameters_to_hashes(value, using)
|
644
|
+
case value
|
645
|
+
when Array
|
646
|
+
value.map { |v| convert_parameters_to_hashes(v, using) }
|
647
|
+
when Hash
|
648
|
+
value.transform_values do |v|
|
649
|
+
convert_parameters_to_hashes(v, using)
|
650
|
+
end.with_indifferent_access
|
651
|
+
when Parameters
|
652
|
+
value.send(using)
|
653
|
+
else
|
654
|
+
value
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
def convert_hashes_to_parameters(key, value)
|
456
659
|
converted = convert_value_to_parameters(value)
|
457
|
-
|
660
|
+
@parameters[key] = converted unless converted.equal?(value)
|
458
661
|
converted
|
459
662
|
end
|
460
663
|
|
461
664
|
def convert_value_to_parameters(value)
|
462
|
-
|
665
|
+
case value
|
666
|
+
when Array
|
667
|
+
return value if converted_arrays.member?(value)
|
463
668
|
converted = value.map { |_| convert_value_to_parameters(_) }
|
464
669
|
converted_arrays << converted
|
465
670
|
converted
|
466
|
-
|
467
|
-
value
|
468
|
-
else
|
671
|
+
when Hash
|
469
672
|
self.class.new(value)
|
673
|
+
else
|
674
|
+
value
|
470
675
|
end
|
471
676
|
end
|
472
677
|
|
473
678
|
def each_element(object)
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
object.
|
479
|
-
|
480
|
-
|
481
|
-
|
679
|
+
case object
|
680
|
+
when Array
|
681
|
+
object.grep(Parameters).map { |el| yield el }.compact
|
682
|
+
when Parameters
|
683
|
+
if object.fields_for_style?
|
684
|
+
hash = object.class.new
|
685
|
+
object.each { |k,v| hash[k] = yield v }
|
686
|
+
hash
|
687
|
+
else
|
688
|
+
yield object
|
689
|
+
end
|
482
690
|
end
|
483
691
|
end
|
484
692
|
|
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
693
|
def unpermitted_parameters!(params)
|
490
694
|
unpermitted_keys = unpermitted_keys(params)
|
491
695
|
if unpermitted_keys.any?
|
@@ -547,15 +751,13 @@ module ActionController
|
|
547
751
|
end
|
548
752
|
|
549
753
|
def array_of_permitted_scalars?(value)
|
550
|
-
if value.is_a?(Array)
|
551
|
-
value
|
754
|
+
if value.is_a?(Array) && value.all? {|element| permitted_scalar?(element)}
|
755
|
+
yield value
|
552
756
|
end
|
553
757
|
end
|
554
758
|
|
555
|
-
def
|
556
|
-
|
557
|
-
params[key] = self[key]
|
558
|
-
end
|
759
|
+
def non_scalar?(value)
|
760
|
+
value.is_a?(Array) || value.is_a?(Parameters)
|
559
761
|
end
|
560
762
|
|
561
763
|
EMPTY_ARRAY = []
|
@@ -565,17 +767,17 @@ module ActionController
|
|
565
767
|
# Slicing filters out non-declared keys.
|
566
768
|
slice(*filter.keys).each do |key, value|
|
567
769
|
next unless value
|
770
|
+
next unless has_key? key
|
568
771
|
|
569
772
|
if filter[key] == EMPTY_ARRAY
|
570
773
|
# Declaration { comment_ids: [] }.
|
571
|
-
|
572
|
-
|
774
|
+
array_of_permitted_scalars?(self[key]) do |val|
|
775
|
+
params[key] = val
|
776
|
+
end
|
777
|
+
elsif non_scalar?(value)
|
573
778
|
# Declaration { user: :name } or { user: [:name, :age, { address: ... }] }.
|
574
779
|
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
|
780
|
+
element.permit(*Array.wrap(filter[key]))
|
579
781
|
end
|
580
782
|
end
|
581
783
|
end
|
@@ -623,7 +825,8 @@ module ActionController
|
|
623
825
|
# end
|
624
826
|
#
|
625
827
|
# 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.
|
828
|
+
# will need to specify which nested attributes should be whitelisted. You might want
|
829
|
+
# to allow +:id+ and +:_destroy+, see ActiveRecord::NestedAttributes for more information.
|
627
830
|
#
|
628
831
|
# class Person
|
629
832
|
# has_many :pets
|
@@ -643,7 +846,7 @@ module ActionController
|
|
643
846
|
# # It's mandatory to specify the nested attributes that should be whitelisted.
|
644
847
|
# # If you use `permit` with just the key that points to the nested attributes hash,
|
645
848
|
# # it will return an empty hash.
|
646
|
-
# params.require(:person).permit(:name, :age, pets_attributes: [ :name, :category ])
|
849
|
+
# params.require(:person).permit(:name, :age, pets_attributes: [ :id, :name, :category ])
|
647
850
|
# end
|
648
851
|
# end
|
649
852
|
#
|
@@ -2,19 +2,8 @@ module ActionController
|
|
2
2
|
module Testing
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
|
-
include RackDelegation
|
6
|
-
|
7
|
-
# TODO : Rewrite tests using controller.headers= to use Rack env
|
8
|
-
def headers=(new_headers)
|
9
|
-
@_response ||= ActionDispatch::Response.new
|
10
|
-
@_response.headers.replace(new_headers)
|
11
|
-
end
|
12
|
-
|
13
5
|
# Behavior specific to functional tests
|
14
6
|
module Functional # :nodoc:
|
15
|
-
def set_response!(request)
|
16
|
-
end
|
17
|
-
|
18
7
|
def recycle!
|
19
8
|
@_url_options = nil
|
20
9
|
self.formats = nil
|
@@ -24,7 +13,7 @@ module ActionController
|
|
24
13
|
|
25
14
|
module ClassMethods
|
26
15
|
def before_filters
|
27
|
-
_process_action_callbacks.find_all{|x| x.kind == :before}.map
|
16
|
+
_process_action_callbacks.find_all{|x| x.kind == :before}.map(&:name)
|
28
17
|
end
|
29
18
|
end
|
30
19
|
end
|
@@ -4,7 +4,10 @@ module ActionController
|
|
4
4
|
#
|
5
5
|
# In addition to <tt>AbstractController::UrlFor</tt>, this module accesses the HTTP layer to define
|
6
6
|
# url options like the +host+. In order to do so, this module requires the host class
|
7
|
-
# to implement +env+
|
7
|
+
# to implement +env+ which needs to be Rack-compatible and +request+
|
8
|
+
# which is either an instance of +ActionDispatch::Request+ or an object
|
9
|
+
# that responds to the +host+, +optional_port+, +protocol+ and
|
10
|
+
# +symbolized_path_parameter+ methods.
|
8
11
|
#
|
9
12
|
# class RootUrl
|
10
13
|
# include ActionController::UrlFor
|
@@ -30,15 +33,19 @@ module ActionController
|
|
30
33
|
:_recall => request.path_parameters
|
31
34
|
}.merge!(super).freeze
|
32
35
|
|
33
|
-
if (same_origin = _routes.equal?(
|
34
|
-
(script_name =
|
35
|
-
(original_script_name =
|
36
|
+
if (same_origin = _routes.equal?(request.routes)) ||
|
37
|
+
(script_name = request.engine_script_name(_routes)) ||
|
38
|
+
(original_script_name = request.original_script_name)
|
36
39
|
|
37
40
|
options = @_url_options.dup
|
38
41
|
if original_script_name
|
39
42
|
options[:original_script_name] = original_script_name
|
40
43
|
else
|
41
|
-
|
44
|
+
if same_origin
|
45
|
+
options[:script_name] = request.script_name.empty? ? "".freeze : request.script_name.dup
|
46
|
+
else
|
47
|
+
options[:script_name] = script_name
|
48
|
+
end
|
42
49
|
end
|
43
50
|
options.freeze
|
44
51
|
else
|