actionpack 5.2.8.1 → 6.1.6.1
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 +383 -346
- data/MIT-LICENSE +1 -2
- data/README.rdoc +4 -3
- data/lib/abstract_controller/base.rb +38 -4
- data/lib/abstract_controller/caching/fragments.rb +6 -22
- data/lib/abstract_controller/caching.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +14 -2
- data/lib/abstract_controller/collector.rb +5 -4
- data/lib/abstract_controller/helpers.rb +106 -90
- data/lib/abstract_controller/railties/routes_helpers.rb +17 -1
- data/lib/abstract_controller/rendering.rb +9 -9
- data/lib/abstract_controller/translation.rb +11 -5
- data/lib/abstract_controller.rb +1 -0
- data/lib/action_controller/api.rb +4 -3
- data/lib/action_controller/base.rb +6 -9
- data/lib/action_controller/caching.rb +1 -3
- data/lib/action_controller/log_subscriber.rb +10 -7
- data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
- data/lib/action_controller/metal/conditional_get.rb +19 -5
- data/lib/action_controller/metal/content_security_policy.rb +1 -2
- data/lib/action_controller/metal/cookies.rb +3 -1
- data/lib/action_controller/metal/data_streaming.rb +6 -7
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +4 -6
- data/lib/action_controller/metal/exceptions.rb +56 -2
- data/lib/action_controller/metal/flash.rb +5 -5
- data/lib/action_controller/metal/head.rb +7 -4
- data/lib/action_controller/metal/helpers.rb +14 -5
- data/lib/action_controller/metal/http_authentication.rb +25 -23
- data/lib/action_controller/metal/implicit_render.rb +5 -15
- data/lib/action_controller/metal/instrumentation.rb +13 -14
- data/lib/action_controller/metal/live.rb +39 -32
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +19 -4
- data/lib/action_controller/metal/parameter_encoding.rb +35 -4
- data/lib/action_controller/metal/params_wrapper.rb +32 -22
- data/lib/action_controller/metal/permissions_policy.rb +46 -0
- data/lib/action_controller/metal/redirecting.rb +6 -6
- data/lib/action_controller/metal/renderers.rb +4 -4
- data/lib/action_controller/metal/rendering.rb +8 -3
- data/lib/action_controller/metal/request_forgery_protection.rb +26 -49
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/streaming.rb +0 -1
- data/lib/action_controller/metal/strong_parameters.rb +168 -59
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/metal.rb +10 -8
- data/lib/action_controller/railties/helpers.rb +1 -1
- data/lib/action_controller/renderer.rb +37 -13
- data/lib/action_controller/template_assertions.rb +1 -1
- data/lib/action_controller/test_case.rb +71 -63
- data/lib/action_controller.rb +7 -4
- data/lib/action_dispatch/http/cache.rb +31 -27
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +34 -18
- data/lib/action_dispatch/http/filter_parameters.rb +9 -8
- data/lib/action_dispatch/http/filter_redirect.rb +2 -3
- data/lib/action_dispatch/http/headers.rb +4 -4
- data/lib/action_dispatch/http/mime_negotiation.rb +26 -13
- data/lib/action_dispatch/http/mime_type.rb +43 -24
- data/lib/action_dispatch/http/parameters.rb +14 -23
- data/lib/action_dispatch/http/permissions_policy.rb +173 -0
- data/lib/action_dispatch/http/request.rb +45 -22
- data/lib/action_dispatch/http/response.rb +45 -25
- data/lib/action_dispatch/http/upload.rb +9 -1
- data/lib/action_dispatch/http/url.rb +82 -82
- data/lib/action_dispatch/journey/formatter.rb +55 -31
- data/lib/action_dispatch/journey/gtg/builder.rb +22 -37
- data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -5
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
- data/lib/action_dispatch/journey/nodes/node.rb +13 -11
- data/lib/action_dispatch/journey/parser.rb +13 -13
- data/lib/action_dispatch/journey/parser.y +1 -1
- data/lib/action_dispatch/journey/path/pattern.rb +19 -21
- data/lib/action_dispatch/journey/route.rb +10 -20
- data/lib/action_dispatch/journey/router/utils.rb +14 -12
- data/lib/action_dispatch/journey/router.rb +26 -34
- data/lib/action_dispatch/journey/routes.rb +0 -2
- data/lib/action_dispatch/journey/scanner.rb +10 -4
- data/lib/action_dispatch/journey/visitors.rb +1 -4
- data/lib/action_dispatch/journey.rb +0 -2
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -4
- data/lib/action_dispatch/middleware/cookies.rb +128 -109
- data/lib/action_dispatch/middleware/debug_exceptions.rb +43 -66
- data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
- data/lib/action_dispatch/middleware/debug_view.rb +66 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -30
- data/lib/action_dispatch/middleware/flash.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +170 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +14 -16
- data/lib/action_dispatch/middleware/request_id.rb +5 -6
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -3
- data/lib/action_dispatch/middleware/session/cookie_store.rb +3 -9
- data/lib/action_dispatch/middleware/show_exceptions.rb +13 -2
- data/lib/action_dispatch/middleware/ssl.rb +20 -15
- data/lib/action_dispatch/middleware/stack.rb +56 -2
- data/lib/action_dispatch/middleware/static.rb +153 -93
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +6 -3
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -1
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +104 -8
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +24 -1
- data/lib/action_dispatch/railtie.rb +8 -2
- data/lib/action_dispatch/request/session.rb +11 -10
- data/lib/action_dispatch/request/utils.rb +26 -2
- data/lib/action_dispatch/routing/inspector.rb +100 -52
- data/lib/action_dispatch/routing/mapper.rb +155 -103
- data/lib/action_dispatch/routing/polymorphic_routes.rb +13 -15
- data/lib/action_dispatch/routing/redirection.rb +4 -4
- data/lib/action_dispatch/routing/route_set.rb +71 -69
- data/lib/action_dispatch/routing/url_for.rb +2 -2
- data/lib/action_dispatch/routing.rb +21 -20
- data/lib/action_dispatch/system_test_case.rb +60 -11
- data/lib/action_dispatch/system_testing/browser.rb +53 -16
- data/lib/action_dispatch/system_testing/driver.rb +11 -3
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +49 -7
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +8 -10
- data/lib/action_dispatch/testing/assertion_response.rb +0 -1
- data/lib/action_dispatch/testing/assertions/response.rb +4 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/integration.rb +60 -28
- data/lib/action_dispatch/testing/request_encoder.rb +2 -2
- data/lib/action_dispatch/testing/test_process.rb +32 -4
- data/lib/action_dispatch/testing/test_request.rb +3 -3
- data/lib/action_dispatch/testing/test_response.rb +4 -32
- data/lib/action_dispatch.rb +9 -3
- data/lib/action_pack/gem_version.rb +3 -3
- data/lib/action_pack.rb +1 -1
- metadata +34 -21
- data/lib/action_controller/metal/force_ssl.rb +0 -99
- data/lib/action_dispatch/http/parameter_filter.rb +0 -86
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -3,7 +3,6 @@
|
|
3
3
|
require "rack/session/abstract/id"
|
4
4
|
require "action_controller/metal/exceptions"
|
5
5
|
require "active_support/security_utils"
|
6
|
-
require "active_support/core_ext/string/strip"
|
7
6
|
|
8
7
|
module ActionController #:nodoc:
|
9
8
|
class InvalidAuthenticityToken < ActionControllerError #:nodoc:
|
@@ -18,7 +17,7 @@ module ActionController #:nodoc:
|
|
18
17
|
# access. When a request reaches your application, \Rails verifies the received
|
19
18
|
# token with the token in the session. All requests are checked except GET requests
|
20
19
|
# as these should be idempotent. Keep in mind that all session-oriented requests
|
21
|
-
#
|
20
|
+
# are CSRF protected by default, including JavaScript and HTML requests.
|
22
21
|
#
|
23
22
|
# Since HTML and JavaScript requests are typically made from the browser, we
|
24
23
|
# need to ensure to verify request authenticity for the web browser. We can
|
@@ -31,31 +30,30 @@ module ActionController #:nodoc:
|
|
31
30
|
# URL on your site. When your JavaScript response loads on their site, it executes.
|
32
31
|
# With carefully crafted JavaScript on their end, sensitive data in your JavaScript
|
33
32
|
# response may be extracted. To prevent this, only XmlHttpRequest (known as XHR or
|
34
|
-
# Ajax) requests are allowed to make
|
33
|
+
# Ajax) requests are allowed to make requests for JavaScript responses.
|
35
34
|
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
# <tt>
|
35
|
+
# Subclasses of <tt>ActionController::Base</tt> are protected by default with the
|
36
|
+
# <tt>:exception</tt> strategy, which raises an
|
37
|
+
# <tt>ActionController::InvalidAuthenticityToken</tt> error on unverified requests.
|
38
|
+
#
|
39
|
+
# APIs may want to disable this behavior since they are typically designed to be
|
40
|
+
# state-less: that is, the request API client handles the session instead of Rails.
|
41
|
+
# One way to achieve this is to use the <tt>:null_session</tt> strategy instead,
|
42
|
+
# which allows unverified requests to be handled, but with an empty session:
|
39
43
|
#
|
40
44
|
# class ApplicationController < ActionController::Base
|
41
|
-
# protect_from_forgery
|
45
|
+
# protect_from_forgery with: :null_session
|
42
46
|
# end
|
43
47
|
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
# <tt>:null_session</tt> method, which provides an empty session
|
47
|
-
# during request.
|
48
|
-
#
|
49
|
-
# We may want to disable CSRF protection for APIs since they are typically
|
50
|
-
# designed to be state-less. That is, the request API client will handle
|
51
|
-
# the session for you instead of Rails.
|
48
|
+
# Note that API only applications don't include this module or a session middleware
|
49
|
+
# by default, and so don't require CSRF protection to be configured.
|
52
50
|
#
|
53
51
|
# The token parameter is named <tt>authenticity_token</tt> by default. The name and
|
54
52
|
# value of this token must be added to every layout that renders forms by including
|
55
53
|
# <tt>csrf_meta_tags</tt> in the HTML +head+.
|
56
54
|
#
|
57
55
|
# Learn more about CSRF attacks and securing your application in the
|
58
|
-
# {Ruby on Rails Security Guide}[
|
56
|
+
# {Ruby on Rails Security Guide}[https://guides.rubyonrails.org/security.html].
|
59
57
|
module RequestForgeryProtection
|
60
58
|
extend ActiveSupport::Concern
|
61
59
|
|
@@ -149,7 +147,6 @@ module ActionController #:nodoc:
|
|
149
147
|
end
|
150
148
|
|
151
149
|
private
|
152
|
-
|
153
150
|
def protection_method_class(name)
|
154
151
|
ActionController::RequestForgeryProtection::ProtectionMethods.const_get(name.to_s.classify)
|
155
152
|
rescue NameError
|
@@ -173,7 +170,6 @@ module ActionController #:nodoc:
|
|
173
170
|
end
|
174
171
|
|
175
172
|
private
|
176
|
-
|
177
173
|
class NullSessionHash < Rack::Session::Abstract::SessionHash #:nodoc:
|
178
174
|
def initialize(req)
|
179
175
|
super(nil, req)
|
@@ -280,7 +276,7 @@ module ActionController #:nodoc:
|
|
280
276
|
|
281
277
|
# Check for cross-origin JavaScript responses.
|
282
278
|
def non_xhr_javascript_response? # :doc:
|
283
|
-
|
279
|
+
%r(\A(?:text|application)/javascript).match?(media_type) && !request.xhr?
|
284
280
|
end
|
285
281
|
|
286
282
|
AUTHENTICITY_TOKEN_LENGTH = 32
|
@@ -390,7 +386,7 @@ module ActionController #:nodoc:
|
|
390
386
|
if per_form_csrf_tokens
|
391
387
|
correct_token = per_form_csrf_token(
|
392
388
|
session,
|
393
|
-
|
389
|
+
request.path.chomp("/"),
|
394
390
|
request.request_method
|
395
391
|
)
|
396
392
|
|
@@ -425,9 +421,14 @@ module ActionController #:nodoc:
|
|
425
421
|
end
|
426
422
|
|
427
423
|
def xor_byte_strings(s1, s2) # :doc:
|
428
|
-
|
429
|
-
s1.
|
430
|
-
|
424
|
+
s2 = s2.dup
|
425
|
+
size = s1.bytesize
|
426
|
+
i = 0
|
427
|
+
while i < size
|
428
|
+
s2.setbyte(i, s1.getbyte(i) ^ s2.getbyte(i))
|
429
|
+
i += 1
|
430
|
+
end
|
431
|
+
s2
|
431
432
|
end
|
432
433
|
|
433
434
|
# The form's authenticity parameter. Override to provide your own.
|
@@ -440,11 +441,11 @@ module ActionController #:nodoc:
|
|
440
441
|
allow_forgery_protection
|
441
442
|
end
|
442
443
|
|
443
|
-
NULL_ORIGIN_MESSAGE =
|
444
|
+
NULL_ORIGIN_MESSAGE = <<~MSG
|
444
445
|
The browser returned a 'null' origin for a request with origin-based forgery protection turned on. This usually
|
445
446
|
means you have the 'no-referrer' Referrer-Policy header enabled, or that the request came from a site that
|
446
447
|
refused to give its origin. This makes it impossible for Rails to verify the source of the requests. Likely the
|
447
|
-
best solution is to change your referrer policy to something less strict like same-origin or strict-
|
448
|
+
best solution is to change your referrer policy to something less strict like same-origin or strict-origin.
|
448
449
|
If you cannot change the referrer policy, you can disable origin checking with the
|
449
450
|
Rails.application.config.action_controller.forgery_protection_origin_check setting.
|
450
451
|
MSG
|
@@ -474,30 +475,6 @@ module ActionController #:nodoc:
|
|
474
475
|
end
|
475
476
|
end
|
476
477
|
|
477
|
-
if RUBY_VERSION.start_with?("2.2")
|
478
|
-
# Backported https://github.com/ruby/ruby/commit/6b6680945ed3274cddbc34fdfd410d74081a3e94
|
479
|
-
using Module.new {
|
480
|
-
refine Base64.singleton_class do
|
481
|
-
def urlsafe_encode64(bin, padding: true)
|
482
|
-
str = strict_encode64(bin).tr("+/", "-_")
|
483
|
-
str = str.delete("=") unless padding
|
484
|
-
str
|
485
|
-
end
|
486
|
-
|
487
|
-
def urlsafe_decode64(str)
|
488
|
-
# NOTE: RFC 4648 does say nothing about unpadded input, but says that
|
489
|
-
# "the excess pad characters MAY also be ignored", so it is inferred that
|
490
|
-
# unpadded input is also acceptable.
|
491
|
-
str = str.tr("-_", "+/")
|
492
|
-
if !str.end_with?("=") && str.length % 4 != 0
|
493
|
-
str = str.ljust((str.length + 3) & ~3, "=")
|
494
|
-
end
|
495
|
-
strict_decode64(str)
|
496
|
-
end
|
497
|
-
end
|
498
|
-
}
|
499
|
-
end
|
500
|
-
|
501
478
|
def encode_csrf_token(csrf_token) # :nodoc:
|
502
479
|
if urlsafe_csrf_tokens
|
503
480
|
Base64.urlsafe_encode64(csrf_token, padding: false)
|
@@ -1,11 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/hash/indifferent_access"
|
4
|
-
require "active_support/core_ext/hash/transform_values"
|
5
4
|
require "active_support/core_ext/array/wrap"
|
6
5
|
require "active_support/core_ext/string/filters"
|
7
6
|
require "active_support/core_ext/object/to_query"
|
8
|
-
require "active_support/rescuable"
|
9
7
|
require "action_dispatch/http/upload"
|
10
8
|
require "rack/test"
|
11
9
|
require "stringio"
|
@@ -21,12 +19,36 @@ module ActionController
|
|
21
19
|
# params.require(:a)
|
22
20
|
# # => ActionController::ParameterMissing: param is missing or the value is empty: a
|
23
21
|
class ParameterMissing < KeyError
|
24
|
-
attr_reader :param # :nodoc:
|
22
|
+
attr_reader :param, :keys # :nodoc:
|
25
23
|
|
26
|
-
def initialize(param) # :nodoc:
|
24
|
+
def initialize(param, keys = nil) # :nodoc:
|
27
25
|
@param = param
|
26
|
+
@keys = keys
|
28
27
|
super("param is missing or the value is empty: #{param}")
|
29
28
|
end
|
29
|
+
|
30
|
+
class Correction
|
31
|
+
def initialize(error)
|
32
|
+
@error = error
|
33
|
+
end
|
34
|
+
|
35
|
+
def corrections
|
36
|
+
if @error.param && @error.keys
|
37
|
+
maybe_these = @error.keys
|
38
|
+
|
39
|
+
maybe_these.sort_by { |n|
|
40
|
+
DidYouMean::Jaro.distance(@error.param.to_s, n)
|
41
|
+
}.reverse.first(4)
|
42
|
+
else
|
43
|
+
[]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# We may not have DYM, and DYM might not let us register error handlers
|
49
|
+
if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
|
50
|
+
DidYouMean.correct_error(self, Correction)
|
51
|
+
end
|
30
52
|
end
|
31
53
|
|
32
54
|
# Raised when a supplied parameter is not expected and
|
@@ -59,7 +81,7 @@ module ActionController
|
|
59
81
|
|
60
82
|
# == Action Controller \Parameters
|
61
83
|
#
|
62
|
-
# Allows you to choose which attributes should be
|
84
|
+
# Allows you to choose which attributes should be permitted for mass updating
|
63
85
|
# and thus prevent accidentally exposing that which shouldn't be exposed.
|
64
86
|
# Provides two methods for this purpose: #require and #permit. The former is
|
65
87
|
# used to mark parameters as required. The latter is used to set the parameter
|
@@ -133,6 +155,15 @@ module ActionController
|
|
133
155
|
#
|
134
156
|
# Returns a hash that can be used as the JSON representation for the parameters.
|
135
157
|
|
158
|
+
##
|
159
|
+
# :method: each_key
|
160
|
+
#
|
161
|
+
# :call-seq:
|
162
|
+
# each_key()
|
163
|
+
#
|
164
|
+
# Calls block once for each key in the parameters, passing the key.
|
165
|
+
# If no block is given, an enumerator is returned instead.
|
166
|
+
|
136
167
|
##
|
137
168
|
# :method: empty?
|
138
169
|
#
|
@@ -173,6 +204,14 @@ module ActionController
|
|
173
204
|
#
|
174
205
|
# Returns true if the given key is present in the parameters.
|
175
206
|
|
207
|
+
##
|
208
|
+
# :method: member?
|
209
|
+
#
|
210
|
+
# :call-seq:
|
211
|
+
# member?(key)
|
212
|
+
#
|
213
|
+
# Returns true if the given key is present in the parameters.
|
214
|
+
|
176
215
|
##
|
177
216
|
# :method: keys
|
178
217
|
#
|
@@ -204,8 +243,8 @@ module ActionController
|
|
204
243
|
# values()
|
205
244
|
#
|
206
245
|
# Returns a new array of the values of the parameters.
|
207
|
-
delegate :keys, :key?, :has_key?, :values, :has_value?, :value?, :empty?, :include?,
|
208
|
-
:as_json, :to_s, to: :@parameters
|
246
|
+
delegate :keys, :key?, :has_key?, :member?, :values, :has_value?, :value?, :empty?, :include?,
|
247
|
+
:as_json, :to_s, :each_key, to: :@parameters
|
209
248
|
|
210
249
|
# By default, never raise an UnpermittedParameters exception if these
|
211
250
|
# params are present. The default includes both 'controller' and 'action'
|
@@ -213,9 +252,15 @@ module ActionController
|
|
213
252
|
# to change these is to specify `always_permitted_parameters` in your
|
214
253
|
# config. For instance:
|
215
254
|
#
|
216
|
-
# config.always_permitted_parameters = %w( controller action format )
|
255
|
+
# config.action_controller.always_permitted_parameters = %w( controller action format )
|
217
256
|
cattr_accessor :always_permitted_parameters, default: %w( controller action )
|
218
257
|
|
258
|
+
class << self
|
259
|
+
def nested_attribute?(key, value) # :nodoc:
|
260
|
+
/\A-?\d+\z/.match?(key) && (value.is_a?(Hash) || value.is_a?(Parameters))
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
219
264
|
# Returns a new instance of <tt>ActionController::Parameters</tt>.
|
220
265
|
# Also, sets the +permitted+ attribute to the default value of
|
221
266
|
# <tt>ActionController::Parameters.permit_all_parameters</tt>.
|
@@ -246,6 +291,11 @@ module ActionController
|
|
246
291
|
@parameters == other
|
247
292
|
end
|
248
293
|
end
|
294
|
+
alias eql? ==
|
295
|
+
|
296
|
+
def hash
|
297
|
+
[@parameters.hash, @permitted].hash
|
298
|
+
end
|
249
299
|
|
250
300
|
# Returns a safe <tt>ActiveSupport::HashWithIndifferentAccess</tt>
|
251
301
|
# representation of the parameters with all unpermitted keys removed.
|
@@ -334,6 +384,7 @@ module ActionController
|
|
334
384
|
# Convert all hashes in values into parameters, then yield each pair in
|
335
385
|
# the same way as <tt>Hash#each_pair</tt>.
|
336
386
|
def each_pair(&block)
|
387
|
+
return to_enum(__callee__) unless block_given?
|
337
388
|
@parameters.each_pair do |key, value|
|
338
389
|
yield [key, convert_hashes_to_parameters(key, value)]
|
339
390
|
end
|
@@ -342,6 +393,17 @@ module ActionController
|
|
342
393
|
end
|
343
394
|
alias_method :each, :each_pair
|
344
395
|
|
396
|
+
# Convert all hashes in values into parameters, then yield each value in
|
397
|
+
# the same way as <tt>Hash#each_value</tt>.
|
398
|
+
def each_value(&block)
|
399
|
+
return to_enum(:each_value) unless block_given?
|
400
|
+
@parameters.each_pair do |key, value|
|
401
|
+
yield convert_hashes_to_parameters(key, value)
|
402
|
+
end
|
403
|
+
|
404
|
+
self
|
405
|
+
end
|
406
|
+
|
345
407
|
# Attribute that keeps track of converted arrays, if any, to avoid double
|
346
408
|
# looping in the common use case permit + mass-assignment. Defined in a
|
347
409
|
# method to instantiate it only if needed.
|
@@ -442,7 +504,7 @@ module ActionController
|
|
442
504
|
if value.present? || value == false
|
443
505
|
value
|
444
506
|
else
|
445
|
-
raise ParameterMissing.new(key)
|
507
|
+
raise ParameterMissing.new(key, @parameters.keys)
|
446
508
|
end
|
447
509
|
end
|
448
510
|
|
@@ -508,7 +570,7 @@ module ActionController
|
|
508
570
|
#
|
509
571
|
# Note that if you use +permit+ in a key that points to a hash,
|
510
572
|
# it won't allow all the hash. You also need to specify which
|
511
|
-
# attributes inside the hash should be
|
573
|
+
# attributes inside the hash should be permitted.
|
512
574
|
#
|
513
575
|
# params = ActionController::Parameters.new({
|
514
576
|
# person: {
|
@@ -579,26 +641,24 @@ module ActionController
|
|
579
641
|
if block_given?
|
580
642
|
yield
|
581
643
|
else
|
582
|
-
args.fetch(0) { raise ActionController::ParameterMissing.new(key) }
|
644
|
+
args.fetch(0) { raise ActionController::ParameterMissing.new(key, @parameters.keys) }
|
583
645
|
end
|
584
646
|
}
|
585
647
|
)
|
586
648
|
end
|
587
649
|
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
@parameters.dig(*keys)
|
601
|
-
end
|
650
|
+
# Extracts the nested parameter from the given +keys+ by calling +dig+
|
651
|
+
# at each step. Returns +nil+ if any intermediate step is +nil+.
|
652
|
+
#
|
653
|
+
# params = ActionController::Parameters.new(foo: { bar: { baz: 1 } })
|
654
|
+
# params.dig(:foo, :bar, :baz) # => 1
|
655
|
+
# params.dig(:foo, :zot, :xyz) # => nil
|
656
|
+
#
|
657
|
+
# params2 = ActionController::Parameters.new(foo: [10, 11, 12])
|
658
|
+
# params2.dig(:foo, 1) # => 11
|
659
|
+
def dig(*keys)
|
660
|
+
convert_hashes_to_parameters(keys.first, @parameters[keys.first])
|
661
|
+
@parameters.dig(*keys)
|
602
662
|
end
|
603
663
|
|
604
664
|
# Returns a new <tt>ActionController::Parameters</tt> instance that
|
@@ -662,22 +722,37 @@ module ActionController
|
|
662
722
|
# Returns a new <tt>ActionController::Parameters</tt> instance with the
|
663
723
|
# results of running +block+ once for every key. The values are unchanged.
|
664
724
|
def transform_keys(&block)
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
else
|
670
|
-
@parameters.transform_keys
|
671
|
-
end
|
725
|
+
return to_enum(:transform_keys) unless block_given?
|
726
|
+
new_instance_with_inherited_permitted_status(
|
727
|
+
@parameters.transform_keys(&block)
|
728
|
+
)
|
672
729
|
end
|
673
730
|
|
674
731
|
# Performs keys transformation and returns the altered
|
675
732
|
# <tt>ActionController::Parameters</tt> instance.
|
676
733
|
def transform_keys!(&block)
|
734
|
+
return to_enum(:transform_keys!) unless block_given?
|
677
735
|
@parameters.transform_keys!(&block)
|
678
736
|
self
|
679
737
|
end
|
680
738
|
|
739
|
+
# Returns a new <tt>ActionController::Parameters</tt> instance with the
|
740
|
+
# results of running +block+ once for every key. This includes the keys
|
741
|
+
# from the root hash and from all nested hashes and arrays. The values are unchanged.
|
742
|
+
def deep_transform_keys(&block)
|
743
|
+
new_instance_with_inherited_permitted_status(
|
744
|
+
@parameters.deep_transform_keys(&block)
|
745
|
+
)
|
746
|
+
end
|
747
|
+
|
748
|
+
# Returns the <tt>ActionController::Parameters</tt> instance changing its keys.
|
749
|
+
# This includes the keys from the root hash and from all nested hashes and arrays.
|
750
|
+
# The values are unchanged.
|
751
|
+
def deep_transform_keys!(&block)
|
752
|
+
@parameters.deep_transform_keys!(&block)
|
753
|
+
self
|
754
|
+
end
|
755
|
+
|
681
756
|
# Deletes a key-value pair from +Parameters+ and returns the value. If
|
682
757
|
# +key+ is not found, returns +nil+ (or, with optional code block, yields
|
683
758
|
# +key+ and returns the result). Cf. +#extract!+, which returns the
|
@@ -712,6 +787,28 @@ module ActionController
|
|
712
787
|
end
|
713
788
|
alias_method :delete_if, :reject!
|
714
789
|
|
790
|
+
# Returns a new instance of <tt>ActionController::Parameters</tt> with +nil+ values removed.
|
791
|
+
def compact
|
792
|
+
new_instance_with_inherited_permitted_status(@parameters.compact)
|
793
|
+
end
|
794
|
+
|
795
|
+
# Removes all +nil+ values in place and returns +self+, or +nil+ if no changes were made.
|
796
|
+
def compact!
|
797
|
+
self if @parameters.compact!
|
798
|
+
end
|
799
|
+
|
800
|
+
# Returns a new instance of <tt>ActionController::Parameters</tt> without the blank values.
|
801
|
+
# Uses Object#blank? for determining if a value is blank.
|
802
|
+
def compact_blank
|
803
|
+
reject { |_k, v| v.blank? }
|
804
|
+
end
|
805
|
+
|
806
|
+
# Removes all blank values in place and returns self.
|
807
|
+
# Uses Object#blank? for determining if a value is blank.
|
808
|
+
def compact_blank!
|
809
|
+
reject! { |_k, v| v.blank? }
|
810
|
+
end
|
811
|
+
|
715
812
|
# Returns values that were assigned to the given +keys+. Note that all the
|
716
813
|
# +Hash+ objects will be converted to <tt>ActionController::Parameters</tt>.
|
717
814
|
def values_at(*keys)
|
@@ -758,7 +855,7 @@ module ActionController
|
|
758
855
|
end
|
759
856
|
|
760
857
|
def inspect
|
761
|
-
"
|
858
|
+
"#<#{self.class} #{@parameters} permitted: #{@permitted}>"
|
762
859
|
end
|
763
860
|
|
764
861
|
def self.hook_into_yaml_loading # :nodoc:
|
@@ -783,7 +880,7 @@ module ActionController
|
|
783
880
|
@permitted = coder.map["ivars"][:@permitted]
|
784
881
|
when "!ruby/object:ActionController::Parameters"
|
785
882
|
# YAML's Object format. Only needed because of the format
|
786
|
-
#
|
883
|
+
# backwards compatibility above, otherwise equivalent to YAML's initialization.
|
787
884
|
@parameters, @permitted = coder.map["parameters"], coder.map["permitted"]
|
788
885
|
end
|
789
886
|
end
|
@@ -798,12 +895,16 @@ module ActionController
|
|
798
895
|
protected
|
799
896
|
attr_reader :parameters
|
800
897
|
|
801
|
-
|
802
|
-
|
898
|
+
attr_writer :permitted
|
899
|
+
|
900
|
+
def nested_attributes?
|
901
|
+
@parameters.any? { |k, v| Parameters.nested_attribute?(k, v) }
|
803
902
|
end
|
804
903
|
|
805
|
-
def
|
806
|
-
|
904
|
+
def each_nested_attribute
|
905
|
+
hash = self.class.new
|
906
|
+
self.each { |k, v| hash[k] = yield v if Parameters.nested_attribute?(k, v) }
|
907
|
+
hash
|
807
908
|
end
|
808
909
|
|
809
910
|
private
|
@@ -839,7 +940,7 @@ module ActionController
|
|
839
940
|
when Array
|
840
941
|
return value if converted_arrays.member?(value)
|
841
942
|
converted = value.map { |_| convert_value_to_parameters(_) }
|
842
|
-
converted_arrays << converted
|
943
|
+
converted_arrays << converted.dup
|
843
944
|
converted
|
844
945
|
when Hash
|
845
946
|
self.class.new(value)
|
@@ -848,15 +949,13 @@ module ActionController
|
|
848
949
|
end
|
849
950
|
end
|
850
951
|
|
851
|
-
def each_element(object)
|
952
|
+
def each_element(object, &block)
|
852
953
|
case object
|
853
954
|
when Array
|
854
955
|
object.grep(Parameters).map { |el| yield el }.compact
|
855
956
|
when Parameters
|
856
|
-
if object.
|
857
|
-
|
858
|
-
object.each { |k, v| hash[k] = yield v }
|
859
|
-
hash
|
957
|
+
if object.nested_attributes?
|
958
|
+
object.each_nested_attribute(&block)
|
860
959
|
else
|
861
960
|
yield object
|
862
961
|
end
|
@@ -884,7 +983,7 @@ module ActionController
|
|
884
983
|
# --- Filtering ----------------------------------------------------------
|
885
984
|
#
|
886
985
|
|
887
|
-
# This is a
|
986
|
+
# This is a list of permitted scalar types that includes the ones
|
888
987
|
# supported in XML and JSON requests.
|
889
988
|
#
|
890
989
|
# This list is in particular used to filter ordinary requests, String goes
|
@@ -911,15 +1010,28 @@ module ActionController
|
|
911
1010
|
PERMITTED_SCALAR_TYPES.any? { |type| value.is_a?(type) }
|
912
1011
|
end
|
913
1012
|
|
914
|
-
|
915
|
-
|
916
|
-
|
1013
|
+
# Adds existing keys to the params if their values are scalar.
|
1014
|
+
#
|
1015
|
+
# For example:
|
1016
|
+
#
|
1017
|
+
# puts self.keys #=> ["zipcode(90210i)"]
|
1018
|
+
# params = {}
|
1019
|
+
#
|
1020
|
+
# permitted_scalar_filter(params, "zipcode")
|
1021
|
+
#
|
1022
|
+
# puts params.keys # => ["zipcode"]
|
1023
|
+
def permitted_scalar_filter(params, permitted_key)
|
1024
|
+
permitted_key = permitted_key.to_s
|
1025
|
+
|
1026
|
+
if has_key?(permitted_key) && permitted_scalar?(self[permitted_key])
|
1027
|
+
params[permitted_key] = self[permitted_key]
|
917
1028
|
end
|
918
1029
|
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
1030
|
+
each_key do |key|
|
1031
|
+
next unless key =~ /\(\d+[if]?\)\z/
|
1032
|
+
next unless $~.pre_match == permitted_key
|
1033
|
+
|
1034
|
+
params[key] = self[key] if permitted_scalar?(self[key])
|
923
1035
|
end
|
924
1036
|
end
|
925
1037
|
|
@@ -1004,8 +1116,8 @@ module ActionController
|
|
1004
1116
|
#
|
1005
1117
|
# It provides an interface for protecting attributes from end-user
|
1006
1118
|
# assignment. This makes Action Controller parameters forbidden
|
1007
|
-
# to be used in Active Model mass assignment until they have been
|
1008
|
-
#
|
1119
|
+
# to be used in Active Model mass assignment until they have been explicitly
|
1120
|
+
# enumerated.
|
1009
1121
|
#
|
1010
1122
|
# In addition, parameters can be marked as required and flow through a
|
1011
1123
|
# predefined raise/rescue flow to end up as a <tt>400 Bad Request</tt> with no
|
@@ -1041,7 +1153,7 @@ module ActionController
|
|
1041
1153
|
# end
|
1042
1154
|
#
|
1043
1155
|
# In order to use <tt>accepts_nested_attributes_for</tt> with Strong \Parameters, you
|
1044
|
-
# will need to specify which nested attributes should be
|
1156
|
+
# will need to specify which nested attributes should be permitted. You might want
|
1045
1157
|
# to allow +:id+ and +:_destroy+, see ActiveRecord::NestedAttributes for more information.
|
1046
1158
|
#
|
1047
1159
|
# class Person
|
@@ -1059,7 +1171,7 @@ module ActionController
|
|
1059
1171
|
# private
|
1060
1172
|
#
|
1061
1173
|
# def person_params
|
1062
|
-
# # It's mandatory to specify the nested attributes that should be
|
1174
|
+
# # It's mandatory to specify the nested attributes that should be permitted.
|
1063
1175
|
# # If you use `permit` with just the key that points to the nested attributes hash,
|
1064
1176
|
# # it will return an empty hash.
|
1065
1177
|
# params.require(:person).permit(:name, :age, pets_attributes: [ :id, :name, :category ])
|
@@ -1069,9 +1181,6 @@ module ActionController
|
|
1069
1181
|
# See ActionController::Parameters.require and ActionController::Parameters.permit
|
1070
1182
|
# for more information.
|
1071
1183
|
module StrongParameters
|
1072
|
-
extend ActiveSupport::Concern
|
1073
|
-
include ActiveSupport::Rescuable
|
1074
|
-
|
1075
1184
|
# Returns a new ActionController::Parameters object that
|
1076
1185
|
# has been instantiated with the <tt>request.parameters</tt>.
|
1077
1186
|
def params
|
@@ -44,7 +44,7 @@ module ActionController
|
|
44
44
|
options[:original_script_name] = original_script_name
|
45
45
|
else
|
46
46
|
if same_origin
|
47
|
-
options[:script_name] = request.script_name.empty? ? ""
|
47
|
+
options[:script_name] = request.script_name.empty? ? "" : request.script_name.dup
|
48
48
|
else
|
49
49
|
options[:script_name] = script_name
|
50
50
|
end
|
@@ -35,7 +35,6 @@ module ActionController
|
|
35
35
|
end
|
36
36
|
|
37
37
|
private
|
38
|
-
|
39
38
|
INCLUDE = ->(list, action) { list.include? action }
|
40
39
|
EXCLUDE = ->(list, action) { !list.include? action }
|
41
40
|
NULL = ->(list, action) { true }
|
@@ -127,7 +126,7 @@ module ActionController
|
|
127
126
|
# ==== Returns
|
128
127
|
# * <tt>string</tt>
|
129
128
|
def self.controller_name
|
130
|
-
@controller_name ||= name.demodulize.
|
129
|
+
@controller_name ||= (name.demodulize.delete_suffix("Controller").underscore unless anonymous?)
|
131
130
|
end
|
132
131
|
|
133
132
|
def self.make_response!(request)
|
@@ -136,7 +135,7 @@ module ActionController
|
|
136
135
|
end
|
137
136
|
end
|
138
137
|
|
139
|
-
def self.
|
138
|
+
def self.action_encoding_template(action) # :nodoc:
|
140
139
|
false
|
141
140
|
end
|
142
141
|
|
@@ -148,7 +147,7 @@ module ActionController
|
|
148
147
|
attr_internal :response, :request
|
149
148
|
delegate :session, to: "@_request"
|
150
149
|
delegate :headers, :status=, :location=, :content_type=,
|
151
|
-
:status, :location, :content_type, to: "@_response"
|
150
|
+
:status, :location, :content_type, :media_type, to: "@_response"
|
152
151
|
|
153
152
|
def initialize
|
154
153
|
@_request = nil
|
@@ -217,10 +216,13 @@ module ActionController
|
|
217
216
|
super
|
218
217
|
end
|
219
218
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
219
|
+
class << self
|
220
|
+
# Pushes the given Rack middleware and its arguments to the bottom of the
|
221
|
+
# middleware stack.
|
222
|
+
def use(*args, &block)
|
223
|
+
middleware_stack.use(*args, &block)
|
224
|
+
end
|
225
|
+
ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
|
224
226
|
end
|
225
227
|
|
226
228
|
# Alias for +middleware_stack+.
|
@@ -7,7 +7,7 @@ module ActionController
|
|
7
7
|
super
|
8
8
|
return unless klass.respond_to?(:helpers_path=)
|
9
9
|
|
10
|
-
if namespace = klass.
|
10
|
+
if namespace = klass.module_parents.detect { |m| m.respond_to?(:railtie_helpers_paths) }
|
11
11
|
paths = namespace.railtie_helpers_paths
|
12
12
|
else
|
13
13
|
paths = ActionController::Helpers.helpers_path
|