omg-actionpack 8.0.0.alpha1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +129 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +57 -0
- data/lib/abstract_controller/asset_paths.rb +14 -0
- data/lib/abstract_controller/base.rb +299 -0
- data/lib/abstract_controller/caching/fragments.rb +149 -0
- data/lib/abstract_controller/caching.rb +68 -0
- data/lib/abstract_controller/callbacks.rb +265 -0
- data/lib/abstract_controller/collector.rb +44 -0
- data/lib/abstract_controller/deprecator.rb +9 -0
- data/lib/abstract_controller/error.rb +8 -0
- data/lib/abstract_controller/helpers.rb +243 -0
- data/lib/abstract_controller/logger.rb +16 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +25 -0
- data/lib/abstract_controller/rendering.rb +126 -0
- data/lib/abstract_controller/translation.rb +42 -0
- data/lib/abstract_controller/url_for.rb +37 -0
- data/lib/abstract_controller.rb +36 -0
- data/lib/action_controller/api/api_rendering.rb +18 -0
- data/lib/action_controller/api.rb +155 -0
- data/lib/action_controller/base.rb +332 -0
- data/lib/action_controller/caching.rb +49 -0
- data/lib/action_controller/deprecator.rb +9 -0
- data/lib/action_controller/form_builder.rb +55 -0
- data/lib/action_controller/log_subscriber.rb +96 -0
- data/lib/action_controller/metal/allow_browser.rb +123 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
- data/lib/action_controller/metal/conditional_get.rb +341 -0
- data/lib/action_controller/metal/content_security_policy.rb +86 -0
- data/lib/action_controller/metal/cookies.rb +20 -0
- data/lib/action_controller/metal/data_streaming.rb +154 -0
- data/lib/action_controller/metal/default_headers.rb +21 -0
- data/lib/action_controller/metal/etag_with_flash.rb +22 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +59 -0
- data/lib/action_controller/metal/exceptions.rb +106 -0
- data/lib/action_controller/metal/flash.rb +67 -0
- data/lib/action_controller/metal/head.rb +67 -0
- data/lib/action_controller/metal/helpers.rb +129 -0
- data/lib/action_controller/metal/http_authentication.rb +565 -0
- data/lib/action_controller/metal/implicit_render.rb +67 -0
- data/lib/action_controller/metal/instrumentation.rb +120 -0
- data/lib/action_controller/metal/live.rb +398 -0
- data/lib/action_controller/metal/logging.rb +22 -0
- data/lib/action_controller/metal/mime_responds.rb +337 -0
- data/lib/action_controller/metal/parameter_encoding.rb +84 -0
- data/lib/action_controller/metal/params_wrapper.rb +312 -0
- data/lib/action_controller/metal/permissions_policy.rb +38 -0
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +251 -0
- data/lib/action_controller/metal/renderers.rb +181 -0
- data/lib/action_controller/metal/rendering.rb +260 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +667 -0
- data/lib/action_controller/metal/rescue.rb +33 -0
- data/lib/action_controller/metal/streaming.rb +183 -0
- data/lib/action_controller/metal/strong_parameters.rb +1546 -0
- data/lib/action_controller/metal/testing.rb +25 -0
- data/lib/action_controller/metal/url_for.rb +65 -0
- data/lib/action_controller/metal.rb +339 -0
- data/lib/action_controller/railtie.rb +149 -0
- data/lib/action_controller/railties/helpers.rb +26 -0
- data/lib/action_controller/renderer.rb +161 -0
- data/lib/action_controller/template_assertions.rb +13 -0
- data/lib/action_controller/test_case.rb +691 -0
- data/lib/action_controller.rb +80 -0
- data/lib/action_dispatch/constants.rb +34 -0
- data/lib/action_dispatch/deprecator.rb +9 -0
- data/lib/action_dispatch/http/cache.rb +249 -0
- data/lib/action_dispatch/http/content_disposition.rb +47 -0
- data/lib/action_dispatch/http/content_security_policy.rb +365 -0
- data/lib/action_dispatch/http/filter_parameters.rb +80 -0
- data/lib/action_dispatch/http/filter_redirect.rb +50 -0
- data/lib/action_dispatch/http/headers.rb +134 -0
- data/lib/action_dispatch/http/mime_negotiation.rb +187 -0
- data/lib/action_dispatch/http/mime_type.rb +389 -0
- data/lib/action_dispatch/http/mime_types.rb +54 -0
- data/lib/action_dispatch/http/parameters.rb +119 -0
- data/lib/action_dispatch/http/permissions_policy.rb +189 -0
- data/lib/action_dispatch/http/rack_cache.rb +67 -0
- data/lib/action_dispatch/http/request.rb +498 -0
- data/lib/action_dispatch/http/response.rb +556 -0
- data/lib/action_dispatch/http/upload.rb +107 -0
- data/lib/action_dispatch/http/url.rb +344 -0
- data/lib/action_dispatch/journey/formatter.rb +226 -0
- data/lib/action_dispatch/journey/gtg/builder.rb +149 -0
- data/lib/action_dispatch/journey/gtg/simulator.rb +50 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +217 -0
- data/lib/action_dispatch/journey/nfa/dot.rb +27 -0
- data/lib/action_dispatch/journey/nodes/node.rb +208 -0
- data/lib/action_dispatch/journey/parser.rb +103 -0
- data/lib/action_dispatch/journey/path/pattern.rb +209 -0
- data/lib/action_dispatch/journey/route.rb +189 -0
- data/lib/action_dispatch/journey/router/utils.rb +105 -0
- data/lib/action_dispatch/journey/router.rb +151 -0
- data/lib/action_dispatch/journey/routes.rb +82 -0
- data/lib/action_dispatch/journey/scanner.rb +70 -0
- data/lib/action_dispatch/journey/visitors.rb +267 -0
- data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
- data/lib/action_dispatch/journey/visualizer/fsm.js +159 -0
- data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
- data/lib/action_dispatch/journey.rb +7 -0
- data/lib/action_dispatch/log_subscriber.rb +25 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
- data/lib/action_dispatch/middleware/callbacks.rb +38 -0
- data/lib/action_dispatch/middleware/cookies.rb +719 -0
- data/lib/action_dispatch/middleware/debug_exceptions.rb +206 -0
- data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
- data/lib/action_dispatch/middleware/debug_view.rb +73 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +350 -0
- data/lib/action_dispatch/middleware/executor.rb +32 -0
- data/lib/action_dispatch/middleware/flash.rb +318 -0
- data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +64 -0
- data/lib/action_dispatch/middleware/reloader.rb +16 -0
- data/lib/action_dispatch/middleware/remote_ip.rb +199 -0
- data/lib/action_dispatch/middleware/request_id.rb +50 -0
- data/lib/action_dispatch/middleware/server_timing.rb +78 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +112 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +66 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +129 -0
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +34 -0
- data/lib/action_dispatch/middleware/show_exceptions.rb +88 -0
- data/lib/action_dispatch/middleware/ssl.rb +180 -0
- data/lib/action_dispatch/middleware/stack.rb +194 -0
- data/lib/action_dispatch/middleware/static.rb +192 -0
- 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 +17 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +62 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +35 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +284 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -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 +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +232 -0
- data/lib/action_dispatch/railtie.rb +77 -0
- data/lib/action_dispatch/request/session.rb +283 -0
- data/lib/action_dispatch/request/utils.rb +109 -0
- data/lib/action_dispatch/routing/endpoint.rb +19 -0
- data/lib/action_dispatch/routing/inspector.rb +323 -0
- data/lib/action_dispatch/routing/mapper.rb +2372 -0
- data/lib/action_dispatch/routing/polymorphic_routes.rb +363 -0
- data/lib/action_dispatch/routing/redirection.rb +218 -0
- data/lib/action_dispatch/routing/route_set.rb +958 -0
- data/lib/action_dispatch/routing/routes_proxy.rb +66 -0
- data/lib/action_dispatch/routing/url_for.rb +244 -0
- data/lib/action_dispatch/routing.rb +262 -0
- data/lib/action_dispatch/system_test_case.rb +206 -0
- data/lib/action_dispatch/system_testing/browser.rb +75 -0
- data/lib/action_dispatch/system_testing/driver.rb +85 -0
- data/lib/action_dispatch/system_testing/server.rb +33 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
- data/lib/action_dispatch/testing/assertion_response.rb +48 -0
- data/lib/action_dispatch/testing/assertions/response.rb +114 -0
- data/lib/action_dispatch/testing/assertions/routing.rb +343 -0
- data/lib/action_dispatch/testing/assertions.rb +25 -0
- data/lib/action_dispatch/testing/integration.rb +694 -0
- data/lib/action_dispatch/testing/request_encoder.rb +60 -0
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +57 -0
- data/lib/action_dispatch/testing/test_request.rb +73 -0
- data/lib/action_dispatch/testing/test_response.rb +58 -0
- data/lib/action_dispatch.rb +147 -0
- data/lib/action_pack/gem_version.rb +19 -0
- data/lib/action_pack/version.rb +12 -0
- data/lib/action_pack.rb +27 -0
- metadata +375 -0
|
@@ -0,0 +1,1546 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
5
|
+
require "active_support/core_ext/hash/indifferent_access"
|
|
6
|
+
require "active_support/core_ext/array/wrap"
|
|
7
|
+
require "active_support/core_ext/string/filters"
|
|
8
|
+
require "active_support/core_ext/object/to_query"
|
|
9
|
+
require "active_support/deep_mergeable"
|
|
10
|
+
require "action_dispatch/http/upload"
|
|
11
|
+
require "rack/test"
|
|
12
|
+
require "stringio"
|
|
13
|
+
require "set"
|
|
14
|
+
require "yaml"
|
|
15
|
+
|
|
16
|
+
module ActionController
|
|
17
|
+
# Raised when a required parameter is missing.
|
|
18
|
+
#
|
|
19
|
+
# params = ActionController::Parameters.new(a: {})
|
|
20
|
+
# params.fetch(:b)
|
|
21
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: b
|
|
22
|
+
# params.require(:a)
|
|
23
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: a
|
|
24
|
+
# params.expect(a: [])
|
|
25
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: a
|
|
26
|
+
class ParameterMissing < KeyError
|
|
27
|
+
attr_reader :param, :keys # :nodoc:
|
|
28
|
+
|
|
29
|
+
def initialize(param, keys = nil) # :nodoc:
|
|
30
|
+
@param = param
|
|
31
|
+
@keys = keys
|
|
32
|
+
super("param is missing or the value is empty or invalid: #{param}")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
|
36
|
+
include DidYouMean::Correctable # :nodoc:
|
|
37
|
+
|
|
38
|
+
def corrections # :nodoc:
|
|
39
|
+
@corrections ||= DidYouMean::SpellChecker.new(dictionary: keys).correct(param.to_s)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Raised from `expect!` when an expected parameter is missing or is of an
|
|
45
|
+
# incompatible type.
|
|
46
|
+
#
|
|
47
|
+
# params = ActionController::Parameters.new(a: {})
|
|
48
|
+
# params.expect!(:a)
|
|
49
|
+
# # => ActionController::ExpectedParameterMissing: param is missing or the value is empty or invalid: a
|
|
50
|
+
class ExpectedParameterMissing < ParameterMissing
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Raised when a supplied parameter is not expected and
|
|
54
|
+
# ActionController::Parameters.action_on_unpermitted_parameters is set to
|
|
55
|
+
# `:raise`.
|
|
56
|
+
#
|
|
57
|
+
# params = ActionController::Parameters.new(a: "123", b: "456")
|
|
58
|
+
# params.permit(:c)
|
|
59
|
+
# # => ActionController::UnpermittedParameters: found unpermitted parameters: :a, :b
|
|
60
|
+
class UnpermittedParameters < IndexError
|
|
61
|
+
attr_reader :params # :nodoc:
|
|
62
|
+
|
|
63
|
+
def initialize(params) # :nodoc:
|
|
64
|
+
@params = params
|
|
65
|
+
super("found unpermitted parameter#{'s' if params.size > 1 }: #{params.map { |e| ":#{e}" }.join(", ")}")
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Raised when a Parameters instance is not marked as permitted and an operation
|
|
70
|
+
# to transform it to hash is called.
|
|
71
|
+
#
|
|
72
|
+
# params = ActionController::Parameters.new(a: "123", b: "456")
|
|
73
|
+
# params.to_h
|
|
74
|
+
# # => ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
|
|
75
|
+
class UnfilteredParameters < ArgumentError
|
|
76
|
+
def initialize # :nodoc:
|
|
77
|
+
super("unable to convert unpermitted parameters to hash")
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Raised when initializing Parameters with keys that aren't strings or symbols.
|
|
82
|
+
#
|
|
83
|
+
# ActionController::Parameters.new(123 => 456)
|
|
84
|
+
# # => ActionController::InvalidParameterKey: all keys must be Strings or Symbols, got: Integer
|
|
85
|
+
class InvalidParameterKey < ArgumentError
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# # Action Controller Parameters
|
|
89
|
+
#
|
|
90
|
+
# Allows you to choose which attributes should be permitted for mass updating
|
|
91
|
+
# and thus prevent accidentally exposing that which shouldn't be exposed.
|
|
92
|
+
#
|
|
93
|
+
# Provides methods for filtering and requiring params:
|
|
94
|
+
#
|
|
95
|
+
# * `expect` to safely permit and require parameters in one step.
|
|
96
|
+
# * `permit` to filter params for mass assignment.
|
|
97
|
+
# * `require` to require a parameter or raise an error.
|
|
98
|
+
#
|
|
99
|
+
# params = ActionController::Parameters.new({
|
|
100
|
+
# person: {
|
|
101
|
+
# name: "Francesco",
|
|
102
|
+
# age: 22,
|
|
103
|
+
# role: "admin"
|
|
104
|
+
# }
|
|
105
|
+
# })
|
|
106
|
+
#
|
|
107
|
+
# permitted = params.expect(person: [:name, :age])
|
|
108
|
+
# permitted # => #<ActionController::Parameters {"name"=>"Francesco", "age"=>22} permitted: true>
|
|
109
|
+
#
|
|
110
|
+
# Person.first.update!(permitted)
|
|
111
|
+
# # => #<Person id: 1, name: "Francesco", age: 22, role: "user">
|
|
112
|
+
#
|
|
113
|
+
# Paramaters provides two options that control the top-level behavior of new
|
|
114
|
+
# instances:
|
|
115
|
+
#
|
|
116
|
+
# * `permit_all_parameters` - If it's `true`, all the parameters will be
|
|
117
|
+
# permitted by default. The default is `false`.
|
|
118
|
+
# * `action_on_unpermitted_parameters` - Controls behavior when parameters
|
|
119
|
+
# that are not explicitly permitted are found. The default value is `:log`
|
|
120
|
+
# in test and development environments, `false` otherwise. The values can
|
|
121
|
+
# be:
|
|
122
|
+
# * `false` to take no action.
|
|
123
|
+
# * `:log` to emit an `ActiveSupport::Notifications.instrument` event on
|
|
124
|
+
# the `unpermitted_parameters.action_controller` topic and log at the
|
|
125
|
+
# DEBUG level.
|
|
126
|
+
# * `:raise` to raise an ActionController::UnpermittedParameters
|
|
127
|
+
# exception.
|
|
128
|
+
#
|
|
129
|
+
# Examples:
|
|
130
|
+
#
|
|
131
|
+
# params = ActionController::Parameters.new
|
|
132
|
+
# params.permitted? # => false
|
|
133
|
+
#
|
|
134
|
+
# ActionController::Parameters.permit_all_parameters = true
|
|
135
|
+
#
|
|
136
|
+
# params = ActionController::Parameters.new
|
|
137
|
+
# params.permitted? # => true
|
|
138
|
+
#
|
|
139
|
+
# params = ActionController::Parameters.new(a: "123", b: "456")
|
|
140
|
+
# params.permit(:c)
|
|
141
|
+
# # => #<ActionController::Parameters {} permitted: true>
|
|
142
|
+
#
|
|
143
|
+
# ActionController::Parameters.action_on_unpermitted_parameters = :raise
|
|
144
|
+
#
|
|
145
|
+
# params = ActionController::Parameters.new(a: "123", b: "456")
|
|
146
|
+
# params.permit(:c)
|
|
147
|
+
# # => ActionController::UnpermittedParameters: found unpermitted keys: a, b
|
|
148
|
+
#
|
|
149
|
+
# Please note that these options *are not thread-safe*. In a multi-threaded
|
|
150
|
+
# environment they should only be set once at boot-time and never mutated at
|
|
151
|
+
# runtime.
|
|
152
|
+
#
|
|
153
|
+
# You can fetch values of `ActionController::Parameters` using either `:key` or
|
|
154
|
+
# `"key"`.
|
|
155
|
+
#
|
|
156
|
+
# params = ActionController::Parameters.new(key: "value")
|
|
157
|
+
# params[:key] # => "value"
|
|
158
|
+
# params["key"] # => "value"
|
|
159
|
+
class Parameters
|
|
160
|
+
include ActiveSupport::DeepMergeable
|
|
161
|
+
|
|
162
|
+
cattr_accessor :permit_all_parameters, instance_accessor: false, default: false
|
|
163
|
+
|
|
164
|
+
cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
|
|
165
|
+
|
|
166
|
+
##
|
|
167
|
+
# :method: deep_merge
|
|
168
|
+
#
|
|
169
|
+
# :call-seq:
|
|
170
|
+
# deep_merge(other_hash, &block)
|
|
171
|
+
#
|
|
172
|
+
# Returns a new `ActionController::Parameters` instance with `self` and
|
|
173
|
+
# `other_hash` merged recursively.
|
|
174
|
+
#
|
|
175
|
+
# Like with `Hash#merge` in the standard library, a block can be provided to
|
|
176
|
+
# merge values.
|
|
177
|
+
#
|
|
178
|
+
#--
|
|
179
|
+
# Implemented by ActiveSupport::DeepMergeable#deep_merge.
|
|
180
|
+
|
|
181
|
+
##
|
|
182
|
+
# :method: deep_merge!
|
|
183
|
+
#
|
|
184
|
+
# :call-seq:
|
|
185
|
+
# deep_merge!(other_hash, &block)
|
|
186
|
+
#
|
|
187
|
+
# Same as `#deep_merge`, but modifies `self`.
|
|
188
|
+
#
|
|
189
|
+
#--
|
|
190
|
+
# Implemented by ActiveSupport::DeepMergeable#deep_merge!.
|
|
191
|
+
|
|
192
|
+
##
|
|
193
|
+
# :method: as_json
|
|
194
|
+
#
|
|
195
|
+
# :call-seq:
|
|
196
|
+
# as_json(options=nil)
|
|
197
|
+
#
|
|
198
|
+
# Returns a hash that can be used as the JSON representation for the parameters.
|
|
199
|
+
|
|
200
|
+
##
|
|
201
|
+
# :method: each_key
|
|
202
|
+
#
|
|
203
|
+
# :call-seq:
|
|
204
|
+
# each_key(&block)
|
|
205
|
+
#
|
|
206
|
+
# Calls block once for each key in the parameters, passing the key. If no block
|
|
207
|
+
# is given, an enumerator is returned instead.
|
|
208
|
+
|
|
209
|
+
##
|
|
210
|
+
# :method: empty?
|
|
211
|
+
#
|
|
212
|
+
# :call-seq:
|
|
213
|
+
# empty?()
|
|
214
|
+
#
|
|
215
|
+
# Returns true if the parameters have no key/value pairs.
|
|
216
|
+
|
|
217
|
+
##
|
|
218
|
+
# :method: exclude?
|
|
219
|
+
#
|
|
220
|
+
# :call-seq:
|
|
221
|
+
# exclude?(key)
|
|
222
|
+
#
|
|
223
|
+
# Returns true if the given key is not present in the parameters.
|
|
224
|
+
|
|
225
|
+
##
|
|
226
|
+
# :method: include?
|
|
227
|
+
#
|
|
228
|
+
# :call-seq:
|
|
229
|
+
# include?(key)
|
|
230
|
+
#
|
|
231
|
+
# Returns true if the given key is present in the parameters.
|
|
232
|
+
|
|
233
|
+
##
|
|
234
|
+
# :method: keys
|
|
235
|
+
#
|
|
236
|
+
# :call-seq:
|
|
237
|
+
# keys()
|
|
238
|
+
#
|
|
239
|
+
# Returns a new array of the keys of the parameters.
|
|
240
|
+
|
|
241
|
+
##
|
|
242
|
+
# :method: to_s
|
|
243
|
+
#
|
|
244
|
+
# :call-seq:
|
|
245
|
+
# to_s()
|
|
246
|
+
#
|
|
247
|
+
# Returns the content of the parameters as a string.
|
|
248
|
+
|
|
249
|
+
delegate :keys, :empty?, :exclude?, :include?,
|
|
250
|
+
:as_json, :to_s, :each_key, to: :@parameters
|
|
251
|
+
|
|
252
|
+
alias_method :has_key?, :include?
|
|
253
|
+
alias_method :key?, :include?
|
|
254
|
+
alias_method :member?, :include?
|
|
255
|
+
|
|
256
|
+
# By default, never raise an UnpermittedParameters exception if these params are
|
|
257
|
+
# present. The default includes both 'controller' and 'action' because they are
|
|
258
|
+
# added by Rails and should be of no concern. One way to change these is to
|
|
259
|
+
# specify `always_permitted_parameters` in your config. For instance:
|
|
260
|
+
#
|
|
261
|
+
# config.action_controller.always_permitted_parameters = %w( controller action format )
|
|
262
|
+
cattr_accessor :always_permitted_parameters, default: %w( controller action )
|
|
263
|
+
|
|
264
|
+
class << self
|
|
265
|
+
def allow_deprecated_parameters_hash_equality
|
|
266
|
+
ActionController.deprecator.warn <<-WARNING.squish
|
|
267
|
+
`Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality` is
|
|
268
|
+
deprecated and will be removed in Rails 8.0.
|
|
269
|
+
WARNING
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def allow_deprecated_parameters_hash_equality=(value)
|
|
273
|
+
ActionController.deprecator.warn <<-WARNING.squish
|
|
274
|
+
`Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality`
|
|
275
|
+
is deprecated and will be removed in Rails 8.0.
|
|
276
|
+
WARNING
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def nested_attribute?(key, value) # :nodoc:
|
|
280
|
+
/\A-?\d+\z/.match?(key) && (value.is_a?(Hash) || value.is_a?(Parameters))
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Returns a new `ActionController::Parameters` instance. Also, sets the
|
|
285
|
+
# `permitted` attribute to the default value of
|
|
286
|
+
# `ActionController::Parameters.permit_all_parameters`.
|
|
287
|
+
#
|
|
288
|
+
# class Person < ActiveRecord::Base
|
|
289
|
+
# end
|
|
290
|
+
#
|
|
291
|
+
# params = ActionController::Parameters.new(name: "Francesco")
|
|
292
|
+
# params.permitted? # => false
|
|
293
|
+
# Person.new(params) # => ActiveModel::ForbiddenAttributesError
|
|
294
|
+
#
|
|
295
|
+
# ActionController::Parameters.permit_all_parameters = true
|
|
296
|
+
#
|
|
297
|
+
# params = ActionController::Parameters.new(name: "Francesco")
|
|
298
|
+
# params.permitted? # => true
|
|
299
|
+
# Person.new(params) # => #<Person id: nil, name: "Francesco">
|
|
300
|
+
def initialize(parameters = {}, logging_context = {})
|
|
301
|
+
parameters.each_key do |key|
|
|
302
|
+
unless key.is_a?(String) || key.is_a?(Symbol)
|
|
303
|
+
raise InvalidParameterKey, "all keys must be Strings or Symbols, got: #{key.class}"
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
@parameters = parameters.with_indifferent_access
|
|
308
|
+
@logging_context = logging_context
|
|
309
|
+
@permitted = self.class.permit_all_parameters
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Returns true if another `Parameters` object contains the same content and
|
|
313
|
+
# permitted flag.
|
|
314
|
+
def ==(other)
|
|
315
|
+
if other.respond_to?(:permitted?)
|
|
316
|
+
permitted? == other.permitted? && parameters == other.parameters
|
|
317
|
+
else
|
|
318
|
+
super
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def eql?(other)
|
|
323
|
+
self.class == other.class &&
|
|
324
|
+
permitted? == other.permitted? &&
|
|
325
|
+
parameters.eql?(other.parameters)
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def hash
|
|
329
|
+
[self.class, @parameters, @permitted].hash
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
# Returns a safe ActiveSupport::HashWithIndifferentAccess representation of the
|
|
333
|
+
# parameters with all unpermitted keys removed.
|
|
334
|
+
#
|
|
335
|
+
# params = ActionController::Parameters.new({
|
|
336
|
+
# name: "Senjougahara Hitagi",
|
|
337
|
+
# oddity: "Heavy stone crab"
|
|
338
|
+
# })
|
|
339
|
+
# params.to_h
|
|
340
|
+
# # => ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
|
|
341
|
+
#
|
|
342
|
+
# safe_params = params.permit(:name)
|
|
343
|
+
# safe_params.to_h # => {"name"=>"Senjougahara Hitagi"}
|
|
344
|
+
def to_h(&block)
|
|
345
|
+
if permitted?
|
|
346
|
+
convert_parameters_to_hashes(@parameters, :to_h, &block)
|
|
347
|
+
else
|
|
348
|
+
raise UnfilteredParameters
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
# Returns a safe `Hash` representation of the parameters with all unpermitted
|
|
353
|
+
# keys removed.
|
|
354
|
+
#
|
|
355
|
+
# params = ActionController::Parameters.new({
|
|
356
|
+
# name: "Senjougahara Hitagi",
|
|
357
|
+
# oddity: "Heavy stone crab"
|
|
358
|
+
# })
|
|
359
|
+
# params.to_hash
|
|
360
|
+
# # => ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
|
|
361
|
+
#
|
|
362
|
+
# safe_params = params.permit(:name)
|
|
363
|
+
# safe_params.to_hash # => {"name"=>"Senjougahara Hitagi"}
|
|
364
|
+
def to_hash
|
|
365
|
+
to_h.to_hash
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# Returns a string representation of the receiver suitable for use as a URL
|
|
369
|
+
# query string:
|
|
370
|
+
#
|
|
371
|
+
# params = ActionController::Parameters.new({
|
|
372
|
+
# name: "David",
|
|
373
|
+
# nationality: "Danish"
|
|
374
|
+
# })
|
|
375
|
+
# params.to_query
|
|
376
|
+
# # => ActionController::UnfilteredParameters: unable to convert unpermitted parameters to hash
|
|
377
|
+
#
|
|
378
|
+
# safe_params = params.permit(:name, :nationality)
|
|
379
|
+
# safe_params.to_query
|
|
380
|
+
# # => "name=David&nationality=Danish"
|
|
381
|
+
#
|
|
382
|
+
# An optional namespace can be passed to enclose key names:
|
|
383
|
+
#
|
|
384
|
+
# params = ActionController::Parameters.new({
|
|
385
|
+
# name: "David",
|
|
386
|
+
# nationality: "Danish"
|
|
387
|
+
# })
|
|
388
|
+
# safe_params = params.permit(:name, :nationality)
|
|
389
|
+
# safe_params.to_query("user")
|
|
390
|
+
# # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
|
|
391
|
+
#
|
|
392
|
+
# The string pairs `"key=value"` that conform the query string are sorted
|
|
393
|
+
# lexicographically in ascending order.
|
|
394
|
+
def to_query(*args)
|
|
395
|
+
to_h.to_query(*args)
|
|
396
|
+
end
|
|
397
|
+
alias_method :to_param, :to_query
|
|
398
|
+
|
|
399
|
+
# Returns an unsafe, unfiltered ActiveSupport::HashWithIndifferentAccess
|
|
400
|
+
# representation of the parameters.
|
|
401
|
+
#
|
|
402
|
+
# params = ActionController::Parameters.new({
|
|
403
|
+
# name: "Senjougahara Hitagi",
|
|
404
|
+
# oddity: "Heavy stone crab"
|
|
405
|
+
# })
|
|
406
|
+
# params.to_unsafe_h
|
|
407
|
+
# # => {"name"=>"Senjougahara Hitagi", "oddity" => "Heavy stone crab"}
|
|
408
|
+
def to_unsafe_h
|
|
409
|
+
convert_parameters_to_hashes(@parameters, :to_unsafe_h)
|
|
410
|
+
end
|
|
411
|
+
alias_method :to_unsafe_hash, :to_unsafe_h
|
|
412
|
+
|
|
413
|
+
# Convert all hashes in values into parameters, then yield each pair in the same
|
|
414
|
+
# way as `Hash#each_pair`.
|
|
415
|
+
def each_pair(&block)
|
|
416
|
+
return to_enum(__callee__) unless block_given?
|
|
417
|
+
@parameters.each_pair do |key, value|
|
|
418
|
+
yield [key, convert_hashes_to_parameters(key, value)]
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
self
|
|
422
|
+
end
|
|
423
|
+
alias_method :each, :each_pair
|
|
424
|
+
|
|
425
|
+
# Convert all hashes in values into parameters, then yield each value in the
|
|
426
|
+
# same way as `Hash#each_value`.
|
|
427
|
+
def each_value(&block)
|
|
428
|
+
return to_enum(:each_value) unless block_given?
|
|
429
|
+
@parameters.each_pair do |key, value|
|
|
430
|
+
yield convert_hashes_to_parameters(key, value)
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
self
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
# Returns a new array of the values of the parameters.
|
|
437
|
+
def values
|
|
438
|
+
to_enum(:each_value).to_a
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
# Attribute that keeps track of converted arrays, if any, to avoid double
|
|
442
|
+
# looping in the common use case permit + mass-assignment. Defined in a method
|
|
443
|
+
# to instantiate it only if needed.
|
|
444
|
+
#
|
|
445
|
+
# Testing membership still loops, but it's going to be faster than our own loop
|
|
446
|
+
# that converts values. Also, we are not going to build a new array object per
|
|
447
|
+
# fetch.
|
|
448
|
+
def converted_arrays
|
|
449
|
+
@converted_arrays ||= Set.new
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
# Returns `true` if the parameter is permitted, `false` otherwise.
|
|
453
|
+
#
|
|
454
|
+
# params = ActionController::Parameters.new
|
|
455
|
+
# params.permitted? # => false
|
|
456
|
+
# params.permit!
|
|
457
|
+
# params.permitted? # => true
|
|
458
|
+
def permitted?
|
|
459
|
+
@permitted
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
# Sets the `permitted` attribute to `true`. This can be used to pass mass
|
|
463
|
+
# assignment. Returns `self`.
|
|
464
|
+
#
|
|
465
|
+
# class Person < ActiveRecord::Base
|
|
466
|
+
# end
|
|
467
|
+
#
|
|
468
|
+
# params = ActionController::Parameters.new(name: "Francesco")
|
|
469
|
+
# params.permitted? # => false
|
|
470
|
+
# Person.new(params) # => ActiveModel::ForbiddenAttributesError
|
|
471
|
+
# params.permit!
|
|
472
|
+
# params.permitted? # => true
|
|
473
|
+
# Person.new(params) # => #<Person id: nil, name: "Francesco">
|
|
474
|
+
def permit!
|
|
475
|
+
each_pair do |key, value|
|
|
476
|
+
Array.wrap(value).flatten.each do |v|
|
|
477
|
+
v.permit! if v.respond_to? :permit!
|
|
478
|
+
end
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
@permitted = true
|
|
482
|
+
self
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
# This method accepts both a single key and an array of keys.
|
|
486
|
+
#
|
|
487
|
+
# When passed a single key, if it exists and its associated value is either
|
|
488
|
+
# present or the singleton `false`, returns said value:
|
|
489
|
+
#
|
|
490
|
+
# ActionController::Parameters.new(person: { name: "Francesco" }).require(:person)
|
|
491
|
+
# # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
|
492
|
+
#
|
|
493
|
+
# Otherwise raises ActionController::ParameterMissing:
|
|
494
|
+
#
|
|
495
|
+
# ActionController::Parameters.new.require(:person)
|
|
496
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty or invalid: person
|
|
497
|
+
#
|
|
498
|
+
# ActionController::Parameters.new(person: nil).require(:person)
|
|
499
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty or invalid: person
|
|
500
|
+
#
|
|
501
|
+
# ActionController::Parameters.new(person: "\t").require(:person)
|
|
502
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty or invalid: person
|
|
503
|
+
#
|
|
504
|
+
# ActionController::Parameters.new(person: {}).require(:person)
|
|
505
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty or invalid: person
|
|
506
|
+
#
|
|
507
|
+
# When given an array of keys, the method tries to require each one of them in
|
|
508
|
+
# order. If it succeeds, an array with the respective return values is returned:
|
|
509
|
+
#
|
|
510
|
+
# params = ActionController::Parameters.new(user: { ... }, profile: { ... })
|
|
511
|
+
# user_params, profile_params = params.require([:user, :profile])
|
|
512
|
+
#
|
|
513
|
+
# Otherwise, the method re-raises the first exception found:
|
|
514
|
+
#
|
|
515
|
+
# params = ActionController::Parameters.new(user: {}, profile: {})
|
|
516
|
+
# user_params, profile_params = params.require([:user, :profile])
|
|
517
|
+
# # ActionController::ParameterMissing: param is missing or the value is empty or invalid: user
|
|
518
|
+
#
|
|
519
|
+
# This method is not recommended for fetching terminal values because it does
|
|
520
|
+
# not permit the values. For example, this can cause problems:
|
|
521
|
+
#
|
|
522
|
+
# # CAREFUL
|
|
523
|
+
# params = ActionController::Parameters.new(person: { name: "Finn" })
|
|
524
|
+
# name = params.require(:person).require(:name) # CAREFUL
|
|
525
|
+
#
|
|
526
|
+
# It is recommended to use `expect` instead:
|
|
527
|
+
#
|
|
528
|
+
# def person_params
|
|
529
|
+
# # params.expect(person: :name).require(:name)
|
|
530
|
+
# end
|
|
531
|
+
#
|
|
532
|
+
def require(key)
|
|
533
|
+
return key.map { |k| require(k) } if key.is_a?(Array)
|
|
534
|
+
value = self[key]
|
|
535
|
+
if value.present? || value == false
|
|
536
|
+
value
|
|
537
|
+
else
|
|
538
|
+
raise ParameterMissing.new(key, @parameters.keys)
|
|
539
|
+
end
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
alias :required :require
|
|
543
|
+
|
|
544
|
+
# Returns a new `ActionController::Parameters` instance that includes only the
|
|
545
|
+
# given `filters` and sets the `permitted` attribute for the object to `true`.
|
|
546
|
+
# This is useful for limiting which attributes should be allowed for mass
|
|
547
|
+
# updating.
|
|
548
|
+
#
|
|
549
|
+
# params = ActionController::Parameters.new(name: "Francesco", age: 22, role: "admin")
|
|
550
|
+
# permitted = params.permit(:name, :age)
|
|
551
|
+
# permitted.permitted? # => true
|
|
552
|
+
# permitted.has_key?(:name) # => true
|
|
553
|
+
# permitted.has_key?(:age) # => true
|
|
554
|
+
# permitted.has_key?(:role) # => false
|
|
555
|
+
#
|
|
556
|
+
# Only permitted scalars pass the filter. For example, given
|
|
557
|
+
#
|
|
558
|
+
# params.permit(:name)
|
|
559
|
+
#
|
|
560
|
+
# `:name` passes if it is a key of `params` whose associated value is of type
|
|
561
|
+
# `String`, `Symbol`, `NilClass`, `Numeric`, `TrueClass`, `FalseClass`, `Date`,
|
|
562
|
+
# `Time`, `DateTime`, `StringIO`, `IO`, ActionDispatch::Http::UploadedFile or
|
|
563
|
+
# `Rack::Test::UploadedFile`. Otherwise, the key `:name` is filtered out.
|
|
564
|
+
#
|
|
565
|
+
# You may declare that the parameter should be an array of permitted scalars by
|
|
566
|
+
# mapping it to an empty array:
|
|
567
|
+
#
|
|
568
|
+
# params = ActionController::Parameters.new(tags: ["rails", "parameters"])
|
|
569
|
+
# params.permit(tags: [])
|
|
570
|
+
#
|
|
571
|
+
# Sometimes it is not possible or convenient to declare the valid keys of a hash
|
|
572
|
+
# parameter or its internal structure. Just map to an empty hash:
|
|
573
|
+
#
|
|
574
|
+
# params.permit(preferences: {})
|
|
575
|
+
#
|
|
576
|
+
# Be careful because this opens the door to arbitrary input. In this case,
|
|
577
|
+
# `permit` ensures values in the returned structure are permitted scalars and
|
|
578
|
+
# filters out anything else.
|
|
579
|
+
#
|
|
580
|
+
# You can also use `permit` on nested parameters:
|
|
581
|
+
#
|
|
582
|
+
# params = ActionController::Parameters.new({
|
|
583
|
+
# person: {
|
|
584
|
+
# name: "Francesco",
|
|
585
|
+
# age: 22,
|
|
586
|
+
# pets: [{
|
|
587
|
+
# name: "Purplish",
|
|
588
|
+
# category: "dogs"
|
|
589
|
+
# }]
|
|
590
|
+
# }
|
|
591
|
+
# })
|
|
592
|
+
#
|
|
593
|
+
# permitted = params.permit(person: [ :name, { pets: :name } ])
|
|
594
|
+
# permitted.permitted? # => true
|
|
595
|
+
# permitted[:person][:name] # => "Francesco"
|
|
596
|
+
# permitted[:person][:age] # => nil
|
|
597
|
+
# permitted[:person][:pets][0][:name] # => "Purplish"
|
|
598
|
+
# permitted[:person][:pets][0][:category] # => nil
|
|
599
|
+
#
|
|
600
|
+
# This has the added benefit of rejecting user-modified inputs that send a
|
|
601
|
+
# string when a hash is expected.
|
|
602
|
+
#
|
|
603
|
+
# When followed by `require`, you can both filter and require parameters
|
|
604
|
+
# following the typical pattern of a Rails form. The `expect` method was
|
|
605
|
+
# made specifically for this use case and is the recommended way to require
|
|
606
|
+
# and permit parameters.
|
|
607
|
+
#
|
|
608
|
+
# permitted = params.expect(person: [:name, :age])
|
|
609
|
+
#
|
|
610
|
+
# When using `permit` and `require` separately, pay careful attention to the
|
|
611
|
+
# order of the method calls.
|
|
612
|
+
#
|
|
613
|
+
# params = ActionController::Parameters.new(person: { name: "Martin", age: 40, role: "admin" })
|
|
614
|
+
# permitted = params.permit(person: [:name, :age]).require(:person) # correct
|
|
615
|
+
#
|
|
616
|
+
# When require is used first, it is possible for users of your application to
|
|
617
|
+
# trigger a NoMethodError when the user, for example, sends a string for :person.
|
|
618
|
+
#
|
|
619
|
+
# params = ActionController::Parameters.new(person: "tampered")
|
|
620
|
+
# permitted = params.require(:person).permit(:name, :age) # not recommended
|
|
621
|
+
# # => NoMethodError: undefined method `permit' for an instance of String
|
|
622
|
+
#
|
|
623
|
+
# Note that if you use `permit` in a key that points to a hash, it won't allow
|
|
624
|
+
# all the hash. You also need to specify which attributes inside the hash should
|
|
625
|
+
# be permitted.
|
|
626
|
+
#
|
|
627
|
+
# params = ActionController::Parameters.new({
|
|
628
|
+
# person: {
|
|
629
|
+
# contact: {
|
|
630
|
+
# email: "none@test.com",
|
|
631
|
+
# phone: "555-1234"
|
|
632
|
+
# }
|
|
633
|
+
# }
|
|
634
|
+
# })
|
|
635
|
+
#
|
|
636
|
+
# params.permit(person: :contact).require(:person)
|
|
637
|
+
# # => #<ActionController::Parameters {} permitted: true>
|
|
638
|
+
#
|
|
639
|
+
# params.permit(person: { contact: :phone }).require(:person)
|
|
640
|
+
# # => #<ActionController::Parameters {"contact"=>#<ActionController::Parameters {"phone"=>"555-1234"} permitted: true>} permitted: true>
|
|
641
|
+
#
|
|
642
|
+
# params.permit(person: { contact: [ :email, :phone ] }).require(:person)
|
|
643
|
+
# # => #<ActionController::Parameters {"contact"=>#<ActionController::Parameters {"email"=>"none@test.com", "phone"=>"555-1234"} permitted: true>} permitted: true>
|
|
644
|
+
#
|
|
645
|
+
# If your parameters specify multiple parameters indexed by a number, you can
|
|
646
|
+
# permit each set of parameters under the numeric key to be the same using the
|
|
647
|
+
# same syntax as permitting a single item.
|
|
648
|
+
#
|
|
649
|
+
# params = ActionController::Parameters.new({
|
|
650
|
+
# person: {
|
|
651
|
+
# '0': {
|
|
652
|
+
# email: "none@test.com",
|
|
653
|
+
# phone: "555-1234"
|
|
654
|
+
# },
|
|
655
|
+
# '1': {
|
|
656
|
+
# email: "nothing@test.com",
|
|
657
|
+
# phone: "555-6789"
|
|
658
|
+
# },
|
|
659
|
+
# }
|
|
660
|
+
# })
|
|
661
|
+
# params.permit(person: [:email]).to_h
|
|
662
|
+
# # => {"person"=>{"0"=>{"email"=>"none@test.com"}, "1"=>{"email"=>"nothing@test.com"}}}
|
|
663
|
+
#
|
|
664
|
+
# If you want to specify what keys you want from each numeric key, you can
|
|
665
|
+
# instead specify each one individually
|
|
666
|
+
#
|
|
667
|
+
# params = ActionController::Parameters.new({
|
|
668
|
+
# person: {
|
|
669
|
+
# '0': {
|
|
670
|
+
# email: "none@test.com",
|
|
671
|
+
# phone: "555-1234"
|
|
672
|
+
# },
|
|
673
|
+
# '1': {
|
|
674
|
+
# email: "nothing@test.com",
|
|
675
|
+
# phone: "555-6789"
|
|
676
|
+
# },
|
|
677
|
+
# }
|
|
678
|
+
# })
|
|
679
|
+
# params.permit(person: { '0': [:email], '1': [:phone]}).to_h
|
|
680
|
+
# # => {"person"=>{"0"=>{"email"=>"none@test.com"}, "1"=>{"phone"=>"555-6789"}}}
|
|
681
|
+
def permit(*filters)
|
|
682
|
+
permit_filters(filters, on_unpermitted: self.class.action_on_unpermitted_parameters, explicit_arrays: false)
|
|
683
|
+
end
|
|
684
|
+
|
|
685
|
+
# `expect` is the preferred way to require and permit parameters.
|
|
686
|
+
# It is safer than the previous recommendation to call `permit` and `require`
|
|
687
|
+
# in sequence, which could allow user triggered 500 errors.
|
|
688
|
+
#
|
|
689
|
+
# `expect` is more strict with types to avoid a number of potential pitfalls
|
|
690
|
+
# that may be encountered with the `.require.permit` pattern.
|
|
691
|
+
#
|
|
692
|
+
# For example:
|
|
693
|
+
#
|
|
694
|
+
# params = ActionController::Parameters.new(comment: { text: "hello" })
|
|
695
|
+
# params.expect(comment: [:text])
|
|
696
|
+
# # => #<ActionController::Parameters { text: "hello" } permitted: true>
|
|
697
|
+
#
|
|
698
|
+
# params = ActionController::Parameters.new(comment: [{ text: "hello" }, { text: "world" }])
|
|
699
|
+
# params.expect(comment: [:text])
|
|
700
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: comment
|
|
701
|
+
#
|
|
702
|
+
# In order to permit an array of parameters, the array must be defined
|
|
703
|
+
# explicitly. Use double array brackets, an array inside an array, to
|
|
704
|
+
# declare that an array of parameters is expected.
|
|
705
|
+
#
|
|
706
|
+
# params = ActionController::Parameters.new(comments: [{ text: "hello" }, { text: "world" }])
|
|
707
|
+
# params.expect(comments: [[:text]])
|
|
708
|
+
# # => [#<ActionController::Parameters { "text" => "hello" } permitted: true>,
|
|
709
|
+
# # #<ActionController::Parameters { "text" => "world" } permitted: true>]
|
|
710
|
+
#
|
|
711
|
+
# params = ActionController::Parameters.new(comments: { text: "hello" })
|
|
712
|
+
# params.expect(comments: [[:text]])
|
|
713
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: comments
|
|
714
|
+
#
|
|
715
|
+
# `expect` is intended to protect against array tampering.
|
|
716
|
+
#
|
|
717
|
+
# params = ActionController::Parameters.new(user: "hack")
|
|
718
|
+
# # The previous way of requiring and permitting parameters will error
|
|
719
|
+
# params.require(:user).permit(:name, pets: [:name]) # wrong
|
|
720
|
+
# # => NoMethodError: undefined method `permit' for an instance of String
|
|
721
|
+
#
|
|
722
|
+
# # similarly with nested parameters
|
|
723
|
+
# params = ActionController::Parameters.new(user: { name: "Martin", pets: { name: "hack" } })
|
|
724
|
+
# user_params = params.require(:user).permit(:name, pets: [:name]) # wrong
|
|
725
|
+
# # user_params[:pets] is expected to be an array but is a hash
|
|
726
|
+
#
|
|
727
|
+
# `expect` solves this by being more strict with types.
|
|
728
|
+
#
|
|
729
|
+
# params = ActionController::Parameters.new(user: "hack")
|
|
730
|
+
# params.expect(user: [ :name, pets: [[:name]] ])
|
|
731
|
+
# # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: user
|
|
732
|
+
#
|
|
733
|
+
# # with nested parameters
|
|
734
|
+
# params = ActionController::Parameters.new(user: { name: "Martin", pets: { name: "hack" } })
|
|
735
|
+
# user_params = params.expect(user: [:name, pets: [[:name]] ])
|
|
736
|
+
# user_params[:pets] # => nil
|
|
737
|
+
#
|
|
738
|
+
# As the examples show, `expect` requires the `:user` key, and any root keys
|
|
739
|
+
# similar to the `.require.permit` pattern. If multiple root keys are
|
|
740
|
+
# expected, they will all be required.
|
|
741
|
+
#
|
|
742
|
+
# params = ActionController::Parameters.new(name: "Martin", pies: [{ type: "dessert", flavor: "pumpkin"}])
|
|
743
|
+
# name, pies = params.expect(:name, pies: [[:type, :flavor]])
|
|
744
|
+
# name # => "Martin"
|
|
745
|
+
# pies # => [#<ActionController::Parameters {"type"=>"dessert", "flavor"=>"pumpkin"} permitted: true>]
|
|
746
|
+
#
|
|
747
|
+
# When called with a hash with multiple keys, `expect` will permit the
|
|
748
|
+
# parameters and require the keys in the order they are given in the hash,
|
|
749
|
+
# returning an array of the permitted parameters.
|
|
750
|
+
#
|
|
751
|
+
# params = ActionController::Parameters.new(subject: { name: "Martin" }, object: { pie: "pumpkin" })
|
|
752
|
+
# subject, object = params.expect(subject: [:name], object: [:pie])
|
|
753
|
+
# subject # => #<ActionController::Parameters {"name"=>"Martin"} permitted: true>
|
|
754
|
+
# object # => #<ActionController::Parameters {"pie"=>"pumpkin"} permitted: true>
|
|
755
|
+
#
|
|
756
|
+
# Besides being more strict about array vs hash params, `expect` uses permit
|
|
757
|
+
# internally, so it will behave similarly.
|
|
758
|
+
#
|
|
759
|
+
# params = ActionController::Parameters.new({
|
|
760
|
+
# person: {
|
|
761
|
+
# name: "Francesco",
|
|
762
|
+
# age: 22,
|
|
763
|
+
# pets: [{
|
|
764
|
+
# name: "Purplish",
|
|
765
|
+
# category: "dogs"
|
|
766
|
+
# }]
|
|
767
|
+
# }
|
|
768
|
+
# })
|
|
769
|
+
#
|
|
770
|
+
# permitted = params.expect(person: [ :name, { pets: [[:name]] } ])
|
|
771
|
+
# permitted.permitted? # => true
|
|
772
|
+
# permitted[:name] # => "Francesco"
|
|
773
|
+
# permitted[:age] # => nil
|
|
774
|
+
# permitted[:pets][0][:name] # => "Purplish"
|
|
775
|
+
# permitted[:pets][0][:category] # => nil
|
|
776
|
+
#
|
|
777
|
+
# An array of permitted scalars may be expected with the following:
|
|
778
|
+
#
|
|
779
|
+
# params = ActionController::Parameters.new(tags: ["rails", "parameters"])
|
|
780
|
+
# permitted = params.expect(tags: [])
|
|
781
|
+
# permitted.permitted? # => true
|
|
782
|
+
# permitted.is_a?(Array) # => true
|
|
783
|
+
# permitted.size # => 2
|
|
784
|
+
#
|
|
785
|
+
def expect(*filters)
|
|
786
|
+
params = permit_filters(filters)
|
|
787
|
+
keys = filters.flatten.flat_map { |f| f.is_a?(Hash) ? f.keys : f }
|
|
788
|
+
values = params.require(keys)
|
|
789
|
+
values.size == 1 ? values.first : values
|
|
790
|
+
end
|
|
791
|
+
|
|
792
|
+
# Same as `expect`, but raises an `ActionController::ExpectedParameterMissing`
|
|
793
|
+
# instead of `ActionController::ParameterMissing`. Unlike `expect` which
|
|
794
|
+
# will render a 400 response, `expect!` will raise an exception that is
|
|
795
|
+
# not handled. This is intended for debugging invalid params for an
|
|
796
|
+
# internal API where incorrectly formatted params would indicate a bug
|
|
797
|
+
# in a client library that should be fixed.
|
|
798
|
+
#
|
|
799
|
+
def expect!(*filters)
|
|
800
|
+
expect(*filters)
|
|
801
|
+
rescue ParameterMissing => e
|
|
802
|
+
raise ExpectedParameterMissing.new(e.param, e.keys)
|
|
803
|
+
end
|
|
804
|
+
|
|
805
|
+
# Returns a parameter for the given `key`. If not found, returns `nil`.
|
|
806
|
+
#
|
|
807
|
+
# params = ActionController::Parameters.new(person: { name: "Francesco" })
|
|
808
|
+
# params[:person] # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
|
809
|
+
# params[:none] # => nil
|
|
810
|
+
def [](key)
|
|
811
|
+
convert_hashes_to_parameters(key, @parameters[key])
|
|
812
|
+
end
|
|
813
|
+
|
|
814
|
+
# Assigns a value to a given `key`. The given key may still get filtered out
|
|
815
|
+
# when #permit is called.
|
|
816
|
+
def []=(key, value)
|
|
817
|
+
@parameters[key] = value
|
|
818
|
+
end
|
|
819
|
+
|
|
820
|
+
# Returns a parameter for the given `key`. If the `key` can't be found, there
|
|
821
|
+
# are several options: With no other arguments, it will raise an
|
|
822
|
+
# ActionController::ParameterMissing error; if a second argument is given, then
|
|
823
|
+
# that is returned (converted to an instance of `ActionController::Parameters`
|
|
824
|
+
# if possible); if a block is given, then that will be run and its result
|
|
825
|
+
# returned.
|
|
826
|
+
#
|
|
827
|
+
# params = ActionController::Parameters.new(person: { name: "Francesco" })
|
|
828
|
+
# params.fetch(:person) # => #<ActionController::Parameters {"name"=>"Francesco"} permitted: false>
|
|
829
|
+
# params.fetch(:none) # => ActionController::ParameterMissing: param is missing or the value is empty or invalid: none
|
|
830
|
+
# params.fetch(:none, {}) # => #<ActionController::Parameters {} permitted: false>
|
|
831
|
+
# params.fetch(:none, "Francesco") # => "Francesco"
|
|
832
|
+
# params.fetch(:none) { "Francesco" } # => "Francesco"
|
|
833
|
+
def fetch(key, *args)
|
|
834
|
+
convert_value_to_parameters(
|
|
835
|
+
@parameters.fetch(key) {
|
|
836
|
+
if block_given?
|
|
837
|
+
yield
|
|
838
|
+
else
|
|
839
|
+
args.fetch(0) { raise ActionController::ParameterMissing.new(key, @parameters.keys) }
|
|
840
|
+
end
|
|
841
|
+
}
|
|
842
|
+
)
|
|
843
|
+
end
|
|
844
|
+
|
|
845
|
+
# Extracts the nested parameter from the given `keys` by calling `dig` at each
|
|
846
|
+
# step. Returns `nil` if any intermediate step is `nil`.
|
|
847
|
+
#
|
|
848
|
+
# params = ActionController::Parameters.new(foo: { bar: { baz: 1 } })
|
|
849
|
+
# params.dig(:foo, :bar, :baz) # => 1
|
|
850
|
+
# params.dig(:foo, :zot, :xyz) # => nil
|
|
851
|
+
#
|
|
852
|
+
# params2 = ActionController::Parameters.new(foo: [10, 11, 12])
|
|
853
|
+
# params2.dig(:foo, 1) # => 11
|
|
854
|
+
def dig(*keys)
|
|
855
|
+
convert_hashes_to_parameters(keys.first, @parameters[keys.first])
|
|
856
|
+
@parameters.dig(*keys)
|
|
857
|
+
end
|
|
858
|
+
|
|
859
|
+
# Returns a new `ActionController::Parameters` instance that includes only the
|
|
860
|
+
# given `keys`. If the given `keys` don't exist, returns an empty hash.
|
|
861
|
+
#
|
|
862
|
+
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
|
863
|
+
# params.slice(:a, :b) # => #<ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
|
|
864
|
+
# params.slice(:d) # => #<ActionController::Parameters {} permitted: false>
|
|
865
|
+
def slice(*keys)
|
|
866
|
+
new_instance_with_inherited_permitted_status(@parameters.slice(*keys))
|
|
867
|
+
end
|
|
868
|
+
|
|
869
|
+
# Returns the current `ActionController::Parameters` instance which contains
|
|
870
|
+
# only the given `keys`.
|
|
871
|
+
def slice!(*keys)
|
|
872
|
+
@parameters.slice!(*keys)
|
|
873
|
+
self
|
|
874
|
+
end
|
|
875
|
+
|
|
876
|
+
# Returns a new `ActionController::Parameters` instance that filters out the
|
|
877
|
+
# given `keys`.
|
|
878
|
+
#
|
|
879
|
+
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
|
880
|
+
# params.except(:a, :b) # => #<ActionController::Parameters {"c"=>3} permitted: false>
|
|
881
|
+
# params.except(:d) # => #<ActionController::Parameters {"a"=>1, "b"=>2, "c"=>3} permitted: false>
|
|
882
|
+
def except(*keys)
|
|
883
|
+
new_instance_with_inherited_permitted_status(@parameters.except(*keys))
|
|
884
|
+
end
|
|
885
|
+
alias_method :without, :except
|
|
886
|
+
|
|
887
|
+
# Removes and returns the key/value pairs matching the given keys.
|
|
888
|
+
#
|
|
889
|
+
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
|
890
|
+
# params.extract!(:a, :b) # => #<ActionController::Parameters {"a"=>1, "b"=>2} permitted: false>
|
|
891
|
+
# params # => #<ActionController::Parameters {"c"=>3} permitted: false>
|
|
892
|
+
def extract!(*keys)
|
|
893
|
+
new_instance_with_inherited_permitted_status(@parameters.extract!(*keys))
|
|
894
|
+
end
|
|
895
|
+
|
|
896
|
+
# Returns a new `ActionController::Parameters` instance with the results of
|
|
897
|
+
# running `block` once for every value. The keys are unchanged.
|
|
898
|
+
#
|
|
899
|
+
# params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
|
|
900
|
+
# params.transform_values { |x| x * 2 }
|
|
901
|
+
# # => #<ActionController::Parameters {"a"=>2, "b"=>4, "c"=>6} permitted: false>
|
|
902
|
+
def transform_values
|
|
903
|
+
return to_enum(:transform_values) unless block_given?
|
|
904
|
+
new_instance_with_inherited_permitted_status(
|
|
905
|
+
@parameters.transform_values { |v| yield convert_value_to_parameters(v) }
|
|
906
|
+
)
|
|
907
|
+
end
|
|
908
|
+
|
|
909
|
+
# Performs values transformation and returns the altered
|
|
910
|
+
# `ActionController::Parameters` instance.
|
|
911
|
+
def transform_values!
|
|
912
|
+
return to_enum(:transform_values!) unless block_given?
|
|
913
|
+
@parameters.transform_values! { |v| yield convert_value_to_parameters(v) }
|
|
914
|
+
self
|
|
915
|
+
end
|
|
916
|
+
|
|
917
|
+
# Returns a new `ActionController::Parameters` instance with the results of
|
|
918
|
+
# running `block` once for every key. The values are unchanged.
|
|
919
|
+
def transform_keys(&block)
|
|
920
|
+
return to_enum(:transform_keys) unless block_given?
|
|
921
|
+
new_instance_with_inherited_permitted_status(
|
|
922
|
+
@parameters.transform_keys(&block)
|
|
923
|
+
)
|
|
924
|
+
end
|
|
925
|
+
|
|
926
|
+
# Performs keys transformation and returns the altered
|
|
927
|
+
# `ActionController::Parameters` instance.
|
|
928
|
+
def transform_keys!(&block)
|
|
929
|
+
return to_enum(:transform_keys!) unless block_given?
|
|
930
|
+
@parameters.transform_keys!(&block)
|
|
931
|
+
self
|
|
932
|
+
end
|
|
933
|
+
|
|
934
|
+
# Returns a new `ActionController::Parameters` instance with the results of
|
|
935
|
+
# running `block` once for every key. This includes the keys from the root hash
|
|
936
|
+
# and from all nested hashes and arrays. The values are unchanged.
|
|
937
|
+
def deep_transform_keys(&block)
|
|
938
|
+
new_instance_with_inherited_permitted_status(
|
|
939
|
+
_deep_transform_keys_in_object(@parameters, &block).to_unsafe_h
|
|
940
|
+
)
|
|
941
|
+
end
|
|
942
|
+
|
|
943
|
+
# Returns the same `ActionController::Parameters` instance with changed keys.
|
|
944
|
+
# This includes the keys from the root hash and from all nested hashes and
|
|
945
|
+
# arrays. The values are unchanged.
|
|
946
|
+
def deep_transform_keys!(&block)
|
|
947
|
+
@parameters = _deep_transform_keys_in_object(@parameters, &block).to_unsafe_h
|
|
948
|
+
self
|
|
949
|
+
end
|
|
950
|
+
|
|
951
|
+
# Deletes a key-value pair from `Parameters` and returns the value. If `key` is
|
|
952
|
+
# not found, returns `nil` (or, with optional code block, yields `key` and
|
|
953
|
+
# returns the result). This method is similar to #extract!, which returns the
|
|
954
|
+
# corresponding `ActionController::Parameters` object.
|
|
955
|
+
def delete(key, &block)
|
|
956
|
+
convert_value_to_parameters(@parameters.delete(key, &block))
|
|
957
|
+
end
|
|
958
|
+
|
|
959
|
+
# Returns a new `ActionController::Parameters` instance with only items that the
|
|
960
|
+
# block evaluates to true.
|
|
961
|
+
def select(&block)
|
|
962
|
+
new_instance_with_inherited_permitted_status(@parameters.select(&block))
|
|
963
|
+
end
|
|
964
|
+
|
|
965
|
+
# Equivalent to Hash#keep_if, but returns `nil` if no changes were made.
|
|
966
|
+
def select!(&block)
|
|
967
|
+
@parameters.select!(&block)
|
|
968
|
+
self
|
|
969
|
+
end
|
|
970
|
+
alias_method :keep_if, :select!
|
|
971
|
+
|
|
972
|
+
# Returns a new `ActionController::Parameters` instance with items that the
|
|
973
|
+
# block evaluates to true removed.
|
|
974
|
+
def reject(&block)
|
|
975
|
+
new_instance_with_inherited_permitted_status(@parameters.reject(&block))
|
|
976
|
+
end
|
|
977
|
+
|
|
978
|
+
# Removes items that the block evaluates to true and returns self.
|
|
979
|
+
def reject!(&block)
|
|
980
|
+
@parameters.reject!(&block)
|
|
981
|
+
self
|
|
982
|
+
end
|
|
983
|
+
alias_method :delete_if, :reject!
|
|
984
|
+
|
|
985
|
+
# Returns a new `ActionController::Parameters` instance with `nil` values
|
|
986
|
+
# removed.
|
|
987
|
+
def compact
|
|
988
|
+
new_instance_with_inherited_permitted_status(@parameters.compact)
|
|
989
|
+
end
|
|
990
|
+
|
|
991
|
+
# Removes all `nil` values in place and returns `self`, or `nil` if no changes
|
|
992
|
+
# were made.
|
|
993
|
+
def compact!
|
|
994
|
+
self if @parameters.compact!
|
|
995
|
+
end
|
|
996
|
+
|
|
997
|
+
# Returns a new `ActionController::Parameters` instance without the blank
|
|
998
|
+
# values. Uses Object#blank? for determining if a value is blank.
|
|
999
|
+
def compact_blank
|
|
1000
|
+
reject { |_k, v| v.blank? }
|
|
1001
|
+
end
|
|
1002
|
+
|
|
1003
|
+
# Removes all blank values in place and returns self. Uses Object#blank? for
|
|
1004
|
+
# determining if a value is blank.
|
|
1005
|
+
def compact_blank!
|
|
1006
|
+
reject! { |_k, v| v.blank? }
|
|
1007
|
+
end
|
|
1008
|
+
|
|
1009
|
+
# Returns true if the given value is present for some key in the parameters.
|
|
1010
|
+
def has_value?(value)
|
|
1011
|
+
each_value.include?(convert_value_to_parameters(value))
|
|
1012
|
+
end
|
|
1013
|
+
|
|
1014
|
+
alias value? has_value?
|
|
1015
|
+
|
|
1016
|
+
# Returns values that were assigned to the given `keys`. Note that all the
|
|
1017
|
+
# `Hash` objects will be converted to `ActionController::Parameters`.
|
|
1018
|
+
def values_at(*keys)
|
|
1019
|
+
convert_value_to_parameters(@parameters.values_at(*keys))
|
|
1020
|
+
end
|
|
1021
|
+
|
|
1022
|
+
# Returns a new `ActionController::Parameters` instance with all keys from
|
|
1023
|
+
# `other_hash` merged into current hash.
|
|
1024
|
+
def merge(other_hash)
|
|
1025
|
+
new_instance_with_inherited_permitted_status(
|
|
1026
|
+
@parameters.merge(other_hash.to_h)
|
|
1027
|
+
)
|
|
1028
|
+
end
|
|
1029
|
+
|
|
1030
|
+
##
|
|
1031
|
+
# :call-seq: merge!(other_hash)
|
|
1032
|
+
#
|
|
1033
|
+
# Returns the current `ActionController::Parameters` instance with `other_hash`
|
|
1034
|
+
# merged into current hash.
|
|
1035
|
+
def merge!(other_hash, &block)
|
|
1036
|
+
@parameters.merge!(other_hash.to_h, &block)
|
|
1037
|
+
self
|
|
1038
|
+
end
|
|
1039
|
+
|
|
1040
|
+
def deep_merge?(other_hash) # :nodoc:
|
|
1041
|
+
other_hash.is_a?(ActiveSupport::DeepMergeable)
|
|
1042
|
+
end
|
|
1043
|
+
|
|
1044
|
+
# Returns a new `ActionController::Parameters` instance with all keys from
|
|
1045
|
+
# current hash merged into `other_hash`.
|
|
1046
|
+
def reverse_merge(other_hash)
|
|
1047
|
+
new_instance_with_inherited_permitted_status(
|
|
1048
|
+
other_hash.to_h.merge(@parameters)
|
|
1049
|
+
)
|
|
1050
|
+
end
|
|
1051
|
+
alias_method :with_defaults, :reverse_merge
|
|
1052
|
+
|
|
1053
|
+
# Returns the current `ActionController::Parameters` instance with current hash
|
|
1054
|
+
# merged into `other_hash`.
|
|
1055
|
+
def reverse_merge!(other_hash)
|
|
1056
|
+
@parameters.merge!(other_hash.to_h) { |key, left, right| left }
|
|
1057
|
+
self
|
|
1058
|
+
end
|
|
1059
|
+
alias_method :with_defaults!, :reverse_merge!
|
|
1060
|
+
|
|
1061
|
+
# This is required by ActiveModel attribute assignment, so that user can pass
|
|
1062
|
+
# `Parameters` to a mass assignment methods in a model. It should not matter as
|
|
1063
|
+
# we are using `HashWithIndifferentAccess` internally.
|
|
1064
|
+
def stringify_keys # :nodoc:
|
|
1065
|
+
dup
|
|
1066
|
+
end
|
|
1067
|
+
|
|
1068
|
+
def inspect
|
|
1069
|
+
"#<#{self.class} #{@parameters} permitted: #{@permitted}>"
|
|
1070
|
+
end
|
|
1071
|
+
|
|
1072
|
+
def self.hook_into_yaml_loading # :nodoc:
|
|
1073
|
+
# Wire up YAML format compatibility with Rails 4.2 and Psych 2.0.8 and 2.0.9+.
|
|
1074
|
+
# Makes the YAML parser call `init_with` when it encounters the keys below
|
|
1075
|
+
# instead of trying its own parsing routines.
|
|
1076
|
+
YAML.load_tags["!ruby/hash-with-ivars:ActionController::Parameters"] = name
|
|
1077
|
+
YAML.load_tags["!ruby/hash:ActionController::Parameters"] = name
|
|
1078
|
+
end
|
|
1079
|
+
hook_into_yaml_loading
|
|
1080
|
+
|
|
1081
|
+
def init_with(coder) # :nodoc:
|
|
1082
|
+
case coder.tag
|
|
1083
|
+
when "!ruby/hash:ActionController::Parameters"
|
|
1084
|
+
# YAML 2.0.8's format where hash instance variables weren't stored.
|
|
1085
|
+
@parameters = coder.map.with_indifferent_access
|
|
1086
|
+
@permitted = false
|
|
1087
|
+
when "!ruby/hash-with-ivars:ActionController::Parameters"
|
|
1088
|
+
# YAML 2.0.9's Hash subclass format where keys and values were stored under an
|
|
1089
|
+
# elements hash and `permitted` within an ivars hash.
|
|
1090
|
+
@parameters = coder.map["elements"].with_indifferent_access
|
|
1091
|
+
@permitted = coder.map["ivars"][:@permitted]
|
|
1092
|
+
when "!ruby/object:ActionController::Parameters"
|
|
1093
|
+
# YAML's Object format. Only needed because of the format backwards
|
|
1094
|
+
# compatibility above, otherwise equivalent to YAML's initialization.
|
|
1095
|
+
@parameters, @permitted = coder.map["parameters"], coder.map["permitted"]
|
|
1096
|
+
end
|
|
1097
|
+
end
|
|
1098
|
+
|
|
1099
|
+
def encode_with(coder) # :nodoc:
|
|
1100
|
+
coder.map = { "parameters" => @parameters, "permitted" => @permitted }
|
|
1101
|
+
end
|
|
1102
|
+
|
|
1103
|
+
# Returns a duplicate `ActionController::Parameters` instance with the same
|
|
1104
|
+
# permitted parameters.
|
|
1105
|
+
def deep_dup
|
|
1106
|
+
self.class.new(@parameters.deep_dup, @logging_context).tap do |duplicate|
|
|
1107
|
+
duplicate.permitted = @permitted
|
|
1108
|
+
end
|
|
1109
|
+
end
|
|
1110
|
+
|
|
1111
|
+
# Returns parameter value for the given `key` separated by `delimiter`.
|
|
1112
|
+
#
|
|
1113
|
+
# params = ActionController::Parameters.new(id: "1_123", tags: "ruby,rails")
|
|
1114
|
+
# params.extract_value(:id) # => ["1", "123"]
|
|
1115
|
+
# params.extract_value(:tags, delimiter: ",") # => ["ruby", "rails"]
|
|
1116
|
+
# params.extract_value(:non_existent_key) # => nil
|
|
1117
|
+
#
|
|
1118
|
+
# Note that if the given `key`'s value contains blank elements, then the
|
|
1119
|
+
# returned array will include empty strings.
|
|
1120
|
+
#
|
|
1121
|
+
# params = ActionController::Parameters.new(tags: "ruby,rails,,web")
|
|
1122
|
+
# params.extract_value(:tags, delimiter: ",") # => ["ruby", "rails", "", "web"]
|
|
1123
|
+
def extract_value(key, delimiter: "_")
|
|
1124
|
+
@parameters[key]&.split(delimiter, -1)
|
|
1125
|
+
end
|
|
1126
|
+
|
|
1127
|
+
protected
|
|
1128
|
+
attr_reader :parameters
|
|
1129
|
+
|
|
1130
|
+
attr_writer :permitted
|
|
1131
|
+
|
|
1132
|
+
def nested_attributes?
|
|
1133
|
+
@parameters.any? { |k, v| Parameters.nested_attribute?(k, v) }
|
|
1134
|
+
end
|
|
1135
|
+
|
|
1136
|
+
def each_nested_attribute
|
|
1137
|
+
hash = self.class.new
|
|
1138
|
+
self.each { |k, v| hash[k] = yield v if Parameters.nested_attribute?(k, v) }
|
|
1139
|
+
hash
|
|
1140
|
+
end
|
|
1141
|
+
|
|
1142
|
+
# Filters self and optionally checks for unpermitted keys
|
|
1143
|
+
def permit_filters(filters, on_unpermitted: nil, explicit_arrays: true)
|
|
1144
|
+
params = self.class.new
|
|
1145
|
+
|
|
1146
|
+
filters.flatten.each do |filter|
|
|
1147
|
+
case filter
|
|
1148
|
+
when Symbol, String
|
|
1149
|
+
# Declaration [:name, "age"]
|
|
1150
|
+
permitted_scalar_filter(params, filter)
|
|
1151
|
+
when Hash
|
|
1152
|
+
# Declaration [{ person: ... }]
|
|
1153
|
+
hash_filter(params, filter, on_unpermitted:, explicit_arrays:)
|
|
1154
|
+
end
|
|
1155
|
+
end
|
|
1156
|
+
|
|
1157
|
+
unpermitted_parameters!(params, on_unpermitted:)
|
|
1158
|
+
|
|
1159
|
+
params.permit!
|
|
1160
|
+
end
|
|
1161
|
+
|
|
1162
|
+
private
|
|
1163
|
+
def new_instance_with_inherited_permitted_status(hash)
|
|
1164
|
+
self.class.new(hash, @logging_context).tap do |new_instance|
|
|
1165
|
+
new_instance.permitted = @permitted
|
|
1166
|
+
end
|
|
1167
|
+
end
|
|
1168
|
+
|
|
1169
|
+
def convert_parameters_to_hashes(value, using, &block)
|
|
1170
|
+
case value
|
|
1171
|
+
when Array
|
|
1172
|
+
value.map { |v| convert_parameters_to_hashes(v, using) }
|
|
1173
|
+
when Hash
|
|
1174
|
+
transformed = value.transform_values do |v|
|
|
1175
|
+
convert_parameters_to_hashes(v, using)
|
|
1176
|
+
end
|
|
1177
|
+
(block_given? ? transformed.to_h(&block) : transformed).with_indifferent_access
|
|
1178
|
+
when Parameters
|
|
1179
|
+
value.send(using)
|
|
1180
|
+
else
|
|
1181
|
+
value
|
|
1182
|
+
end
|
|
1183
|
+
end
|
|
1184
|
+
|
|
1185
|
+
def convert_hashes_to_parameters(key, value)
|
|
1186
|
+
converted = convert_value_to_parameters(value)
|
|
1187
|
+
@parameters[key] = converted unless converted.equal?(value)
|
|
1188
|
+
converted
|
|
1189
|
+
end
|
|
1190
|
+
|
|
1191
|
+
def convert_value_to_parameters(value)
|
|
1192
|
+
case value
|
|
1193
|
+
when Array
|
|
1194
|
+
return value if converted_arrays.member?(value)
|
|
1195
|
+
converted = value.map { |_| convert_value_to_parameters(_) }
|
|
1196
|
+
converted_arrays << converted.dup
|
|
1197
|
+
converted
|
|
1198
|
+
when Hash
|
|
1199
|
+
self.class.new(value, @logging_context)
|
|
1200
|
+
else
|
|
1201
|
+
value
|
|
1202
|
+
end
|
|
1203
|
+
end
|
|
1204
|
+
|
|
1205
|
+
def _deep_transform_keys_in_object(object, &block)
|
|
1206
|
+
case object
|
|
1207
|
+
when Hash
|
|
1208
|
+
object.each_with_object(self.class.new) do |(key, value), result|
|
|
1209
|
+
result[yield(key)] = _deep_transform_keys_in_object(value, &block)
|
|
1210
|
+
end
|
|
1211
|
+
when Parameters
|
|
1212
|
+
if object.permitted?
|
|
1213
|
+
object.to_h.deep_transform_keys(&block)
|
|
1214
|
+
else
|
|
1215
|
+
object.to_unsafe_h.deep_transform_keys(&block)
|
|
1216
|
+
end
|
|
1217
|
+
when Array
|
|
1218
|
+
object.map { |e| _deep_transform_keys_in_object(e, &block) }
|
|
1219
|
+
else
|
|
1220
|
+
object
|
|
1221
|
+
end
|
|
1222
|
+
end
|
|
1223
|
+
|
|
1224
|
+
def _deep_transform_keys_in_object!(object, &block)
|
|
1225
|
+
case object
|
|
1226
|
+
when Hash
|
|
1227
|
+
object.keys.each do |key|
|
|
1228
|
+
value = object.delete(key)
|
|
1229
|
+
object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
|
|
1230
|
+
end
|
|
1231
|
+
object
|
|
1232
|
+
when Parameters
|
|
1233
|
+
if object.permitted?
|
|
1234
|
+
object.to_h.deep_transform_keys!(&block)
|
|
1235
|
+
else
|
|
1236
|
+
object.to_unsafe_h.deep_transform_keys!(&block)
|
|
1237
|
+
end
|
|
1238
|
+
when Array
|
|
1239
|
+
object.map! { |e| _deep_transform_keys_in_object!(e, &block) }
|
|
1240
|
+
else
|
|
1241
|
+
object
|
|
1242
|
+
end
|
|
1243
|
+
end
|
|
1244
|
+
|
|
1245
|
+
def specify_numeric_keys?(filter)
|
|
1246
|
+
if filter.respond_to?(:keys)
|
|
1247
|
+
filter.keys.any? { |key| /\A-?\d+\z/.match?(key) }
|
|
1248
|
+
end
|
|
1249
|
+
end
|
|
1250
|
+
|
|
1251
|
+
# When an array is expected, you must specify an array explicitly
|
|
1252
|
+
# using the following format:
|
|
1253
|
+
#
|
|
1254
|
+
# params.expect(comments: [[:flavor]])
|
|
1255
|
+
#
|
|
1256
|
+
# Which will match only the following array formats:
|
|
1257
|
+
#
|
|
1258
|
+
# { pies: [{ flavor: "rhubarb" }, { flavor: "apple" }] }
|
|
1259
|
+
# { pies: { "0" => { flavor: "key lime" }, "1" => { flavor: "mince" } } }
|
|
1260
|
+
#
|
|
1261
|
+
# When using `permit`, arrays are specified the same way as hashes:
|
|
1262
|
+
#
|
|
1263
|
+
# params.expect(pies: [:flavor])
|
|
1264
|
+
#
|
|
1265
|
+
# In this case, `permit` would also allow matching with a hash (or vice versa):
|
|
1266
|
+
#
|
|
1267
|
+
# { pies: { flavor: "cherry" } }
|
|
1268
|
+
#
|
|
1269
|
+
def array_filter?(filter)
|
|
1270
|
+
filter.is_a?(Array) && filter.size == 1 && filter.first.is_a?(Array)
|
|
1271
|
+
end
|
|
1272
|
+
|
|
1273
|
+
# Called when an explicit array filter is encountered.
|
|
1274
|
+
def each_array_element(object, filter, &block)
|
|
1275
|
+
case object
|
|
1276
|
+
when Array
|
|
1277
|
+
object.grep(Parameters).filter_map(&block)
|
|
1278
|
+
when Parameters
|
|
1279
|
+
if object.nested_attributes? && !specify_numeric_keys?(filter)
|
|
1280
|
+
object.each_nested_attribute(&block)
|
|
1281
|
+
end
|
|
1282
|
+
end
|
|
1283
|
+
end
|
|
1284
|
+
|
|
1285
|
+
def unpermitted_parameters!(params, on_unpermitted: self.class.action_on_unpermitted_parameters)
|
|
1286
|
+
return unless on_unpermitted
|
|
1287
|
+
unpermitted_keys = unpermitted_keys(params)
|
|
1288
|
+
if unpermitted_keys.any?
|
|
1289
|
+
case on_unpermitted
|
|
1290
|
+
when :log
|
|
1291
|
+
name = "unpermitted_parameters.action_controller"
|
|
1292
|
+
ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys, context: @logging_context)
|
|
1293
|
+
when :raise
|
|
1294
|
+
raise ActionController::UnpermittedParameters.new(unpermitted_keys)
|
|
1295
|
+
end
|
|
1296
|
+
end
|
|
1297
|
+
end
|
|
1298
|
+
|
|
1299
|
+
def unpermitted_keys(params)
|
|
1300
|
+
keys - params.keys - always_permitted_parameters
|
|
1301
|
+
end
|
|
1302
|
+
|
|
1303
|
+
#
|
|
1304
|
+
# --- Filtering ----------------------------------------------------------
|
|
1305
|
+
#
|
|
1306
|
+
# This is a list of permitted scalar types that includes the ones supported in
|
|
1307
|
+
# XML and JSON requests.
|
|
1308
|
+
#
|
|
1309
|
+
# This list is in particular used to filter ordinary requests, String goes as
|
|
1310
|
+
# first element to quickly short-circuit the common case.
|
|
1311
|
+
#
|
|
1312
|
+
# If you modify this collection please update the one in the #permit doc as
|
|
1313
|
+
# well.
|
|
1314
|
+
PERMITTED_SCALAR_TYPES = [
|
|
1315
|
+
String,
|
|
1316
|
+
Symbol,
|
|
1317
|
+
NilClass,
|
|
1318
|
+
Numeric,
|
|
1319
|
+
TrueClass,
|
|
1320
|
+
FalseClass,
|
|
1321
|
+
Date,
|
|
1322
|
+
Time,
|
|
1323
|
+
# DateTimes are Dates, we document the type but avoid the redundant check.
|
|
1324
|
+
StringIO,
|
|
1325
|
+
IO,
|
|
1326
|
+
ActionDispatch::Http::UploadedFile,
|
|
1327
|
+
Rack::Test::UploadedFile,
|
|
1328
|
+
]
|
|
1329
|
+
|
|
1330
|
+
def permitted_scalar?(value)
|
|
1331
|
+
PERMITTED_SCALAR_TYPES.any? { |type| value.is_a?(type) }
|
|
1332
|
+
end
|
|
1333
|
+
|
|
1334
|
+
# Adds existing keys to the params if their values are scalar.
|
|
1335
|
+
#
|
|
1336
|
+
# For example:
|
|
1337
|
+
#
|
|
1338
|
+
# puts self.keys #=> ["zipcode(90210i)"]
|
|
1339
|
+
# params = {}
|
|
1340
|
+
#
|
|
1341
|
+
# permitted_scalar_filter(params, "zipcode")
|
|
1342
|
+
#
|
|
1343
|
+
# puts params.keys # => ["zipcode"]
|
|
1344
|
+
def permitted_scalar_filter(params, permitted_key)
|
|
1345
|
+
permitted_key = permitted_key.to_s
|
|
1346
|
+
|
|
1347
|
+
if has_key?(permitted_key) && permitted_scalar?(self[permitted_key])
|
|
1348
|
+
params[permitted_key] = self[permitted_key]
|
|
1349
|
+
end
|
|
1350
|
+
|
|
1351
|
+
each_key do |key|
|
|
1352
|
+
next unless key =~ /\(\d+[if]?\)\z/
|
|
1353
|
+
next unless $~.pre_match == permitted_key
|
|
1354
|
+
|
|
1355
|
+
params[key] = self[key] if permitted_scalar?(self[key])
|
|
1356
|
+
end
|
|
1357
|
+
end
|
|
1358
|
+
|
|
1359
|
+
def non_scalar?(value)
|
|
1360
|
+
value.is_a?(Array) || value.is_a?(Parameters)
|
|
1361
|
+
end
|
|
1362
|
+
|
|
1363
|
+
EMPTY_ARRAY = [] # :nodoc:
|
|
1364
|
+
EMPTY_HASH = {} # :nodoc:
|
|
1365
|
+
def hash_filter(params, filter, on_unpermitted: self.class.action_on_unpermitted_parameters, explicit_arrays: false)
|
|
1366
|
+
filter = filter.with_indifferent_access
|
|
1367
|
+
|
|
1368
|
+
# Slicing filters out non-declared keys.
|
|
1369
|
+
slice(*filter.keys).each do |key, value|
|
|
1370
|
+
next unless value
|
|
1371
|
+
next unless has_key? key
|
|
1372
|
+
result = permit_value(value, filter[key], on_unpermitted:, explicit_arrays:)
|
|
1373
|
+
params[key] = result unless result.nil?
|
|
1374
|
+
end
|
|
1375
|
+
end
|
|
1376
|
+
|
|
1377
|
+
def permit_value(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1378
|
+
if filter == EMPTY_ARRAY # Declaration { comment_ids: [] }.
|
|
1379
|
+
permit_array_of_scalars(value)
|
|
1380
|
+
elsif filter == EMPTY_HASH # Declaration { preferences: {} }.
|
|
1381
|
+
permit_hash(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1382
|
+
elsif array_filter?(filter) # Declaration { comments: [[:text]] }
|
|
1383
|
+
permit_array_of_hashes(value, filter.first, on_unpermitted:, explicit_arrays:)
|
|
1384
|
+
elsif explicit_arrays # Declaration { user: { address: ... } } or { user: [:name, ...] } (only allows hash value)
|
|
1385
|
+
permit_hash(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1386
|
+
elsif non_scalar?(value) # Declaration { user: { address: ... } } or { user: [:name, ...] }
|
|
1387
|
+
permit_hash_or_array(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1388
|
+
end
|
|
1389
|
+
end
|
|
1390
|
+
|
|
1391
|
+
def permit_array_of_scalars(value)
|
|
1392
|
+
value if value.is_a?(Array) && value.all? { |element| permitted_scalar?(element) }
|
|
1393
|
+
end
|
|
1394
|
+
|
|
1395
|
+
def permit_array_of_hashes(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1396
|
+
each_array_element(value, filter) do |element|
|
|
1397
|
+
element.permit_filters(Array.wrap(filter), on_unpermitted:, explicit_arrays:)
|
|
1398
|
+
end
|
|
1399
|
+
end
|
|
1400
|
+
|
|
1401
|
+
def permit_hash(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1402
|
+
return unless value.is_a?(Parameters)
|
|
1403
|
+
|
|
1404
|
+
if filter == EMPTY_HASH
|
|
1405
|
+
permit_any_in_parameters(value)
|
|
1406
|
+
else
|
|
1407
|
+
value.permit_filters(Array.wrap(filter), on_unpermitted:, explicit_arrays:)
|
|
1408
|
+
end
|
|
1409
|
+
end
|
|
1410
|
+
|
|
1411
|
+
def permit_hash_or_array(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1412
|
+
permit_array_of_hashes(value, filter, on_unpermitted:, explicit_arrays:) ||
|
|
1413
|
+
permit_hash(value, filter, on_unpermitted:, explicit_arrays:)
|
|
1414
|
+
end
|
|
1415
|
+
|
|
1416
|
+
def permit_any_in_parameters(params)
|
|
1417
|
+
self.class.new.tap do |sanitized|
|
|
1418
|
+
params.each do |key, value|
|
|
1419
|
+
case value
|
|
1420
|
+
when ->(v) { permitted_scalar?(v) }
|
|
1421
|
+
sanitized[key] = value
|
|
1422
|
+
when Array
|
|
1423
|
+
sanitized[key] = permit_any_in_array(value)
|
|
1424
|
+
when Parameters
|
|
1425
|
+
sanitized[key] = permit_any_in_parameters(value)
|
|
1426
|
+
else
|
|
1427
|
+
# Filter this one out.
|
|
1428
|
+
end
|
|
1429
|
+
end
|
|
1430
|
+
end
|
|
1431
|
+
end
|
|
1432
|
+
|
|
1433
|
+
def permit_any_in_array(array)
|
|
1434
|
+
[].tap do |sanitized|
|
|
1435
|
+
array.each do |element|
|
|
1436
|
+
case element
|
|
1437
|
+
when ->(e) { permitted_scalar?(e) }
|
|
1438
|
+
sanitized << element
|
|
1439
|
+
when Array
|
|
1440
|
+
sanitized << permit_any_in_array(element)
|
|
1441
|
+
when Parameters
|
|
1442
|
+
sanitized << permit_any_in_parameters(element)
|
|
1443
|
+
else
|
|
1444
|
+
# Filter this one out.
|
|
1445
|
+
end
|
|
1446
|
+
end
|
|
1447
|
+
end
|
|
1448
|
+
end
|
|
1449
|
+
|
|
1450
|
+
def initialize_copy(source)
|
|
1451
|
+
super
|
|
1452
|
+
@parameters = @parameters.dup
|
|
1453
|
+
end
|
|
1454
|
+
end
|
|
1455
|
+
|
|
1456
|
+
# # Strong Parameters
|
|
1457
|
+
#
|
|
1458
|
+
# It provides an interface for protecting attributes from end-user assignment.
|
|
1459
|
+
# This makes Action Controller parameters forbidden to be used in Active Model
|
|
1460
|
+
# mass assignment until they have been explicitly enumerated.
|
|
1461
|
+
#
|
|
1462
|
+
# In addition, parameters can be marked as required and flow through a
|
|
1463
|
+
# predefined raise/rescue flow to end up as a `400 Bad Request` with no effort.
|
|
1464
|
+
#
|
|
1465
|
+
# class PeopleController < ActionController::Base
|
|
1466
|
+
# # Using "Person.create(params[:person])" would raise an
|
|
1467
|
+
# # ActiveModel::ForbiddenAttributesError exception because it'd
|
|
1468
|
+
# # be using mass assignment without an explicit permit step.
|
|
1469
|
+
# # This is the recommended form:
|
|
1470
|
+
# def create
|
|
1471
|
+
# Person.create(person_params)
|
|
1472
|
+
# end
|
|
1473
|
+
#
|
|
1474
|
+
# # This will pass with flying colors as long as there's a person key in the
|
|
1475
|
+
# # parameters, otherwise it'll raise an ActionController::ParameterMissing
|
|
1476
|
+
# # exception, which will get caught by ActionController::Base and turned
|
|
1477
|
+
# # into a 400 Bad Request reply.
|
|
1478
|
+
# def update
|
|
1479
|
+
# redirect_to current_account.people.find(params[:id]).tap { |person|
|
|
1480
|
+
# person.update!(person_params)
|
|
1481
|
+
# }
|
|
1482
|
+
# end
|
|
1483
|
+
#
|
|
1484
|
+
# private
|
|
1485
|
+
# # Using a private method to encapsulate the permissible parameters is
|
|
1486
|
+
# # a good pattern since you'll be able to reuse the same permit
|
|
1487
|
+
# # list between create and update. Also, you can specialize this method
|
|
1488
|
+
# # with per-user checking of permissible attributes.
|
|
1489
|
+
# def person_params
|
|
1490
|
+
# params.expect(person: [:name, :age])
|
|
1491
|
+
# end
|
|
1492
|
+
# end
|
|
1493
|
+
#
|
|
1494
|
+
# In order to use `accepts_nested_attributes_for` with Strong Parameters, you
|
|
1495
|
+
# will need to specify which nested attributes should be permitted. You might
|
|
1496
|
+
# want to allow `:id` and `:_destroy`, see ActiveRecord::NestedAttributes for
|
|
1497
|
+
# more information.
|
|
1498
|
+
#
|
|
1499
|
+
# class Person
|
|
1500
|
+
# has_many :pets
|
|
1501
|
+
# accepts_nested_attributes_for :pets
|
|
1502
|
+
# end
|
|
1503
|
+
#
|
|
1504
|
+
# class PeopleController < ActionController::Base
|
|
1505
|
+
# def create
|
|
1506
|
+
# Person.create(person_params)
|
|
1507
|
+
# end
|
|
1508
|
+
#
|
|
1509
|
+
# ...
|
|
1510
|
+
#
|
|
1511
|
+
# private
|
|
1512
|
+
#
|
|
1513
|
+
# def person_params
|
|
1514
|
+
# # It's mandatory to specify the nested attributes that should be permitted.
|
|
1515
|
+
# # If you use `permit` with just the key that points to the nested attributes hash,
|
|
1516
|
+
# # it will return an empty hash.
|
|
1517
|
+
# params.expect(person: [ :name, :age, pets_attributes: [ :id, :name, :category ] ])
|
|
1518
|
+
# end
|
|
1519
|
+
# end
|
|
1520
|
+
#
|
|
1521
|
+
# See ActionController::Parameters.expect,
|
|
1522
|
+
# See ActionController::Parameters.require, and
|
|
1523
|
+
# ActionController::Parameters.permit for more information.
|
|
1524
|
+
module StrongParameters
|
|
1525
|
+
# Returns a new ActionController::Parameters object that has been instantiated
|
|
1526
|
+
# with the `request.parameters`.
|
|
1527
|
+
def params
|
|
1528
|
+
@_params ||= begin
|
|
1529
|
+
context = {
|
|
1530
|
+
controller: self.class.name,
|
|
1531
|
+
action: action_name,
|
|
1532
|
+
request: request,
|
|
1533
|
+
params: request.filtered_parameters
|
|
1534
|
+
}
|
|
1535
|
+
Parameters.new(request.parameters, context)
|
|
1536
|
+
end
|
|
1537
|
+
end
|
|
1538
|
+
|
|
1539
|
+
# Assigns the given `value` to the `params` hash. If `value` is a Hash, this
|
|
1540
|
+
# will create an ActionController::Parameters object that has been instantiated
|
|
1541
|
+
# with the given `value` hash.
|
|
1542
|
+
def params=(value)
|
|
1543
|
+
@_params = value.is_a?(Hash) ? Parameters.new(value) : value
|
|
1544
|
+
end
|
|
1545
|
+
end
|
|
1546
|
+
end
|