Skip to content

Commit 3a32f44

Browse files
authored
Merge pull request rails#41809 from bbuchalter/bb.improved_strong_params_logging
Provide context when logging unpermitted parameters
2 parents c6ee8c5 + 6be9c49 commit 3a32f44

File tree

6 files changed

+45
-24
lines changed

6 files changed

+45
-24
lines changed

actionpack/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
* Expand payload of `unpermitted_parameters.action_controller` instrumentation to allow subscribers to
2+
know which controller action received unpermitted parameters.
3+
4+
*bbuchalter*
5+
16
* Add `ActionController::Live#send_stream` that makes it more convenient to send generated streams:
27

38
```ruby

actionpack/lib/action_controller/log_subscriber.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ def send_data(event)
5656
def unpermitted_parameters(event)
5757
debug do
5858
unpermitted_keys = event.payload[:keys]
59-
color("Unpermitted parameter#{'s' if unpermitted_keys.size > 1}: #{unpermitted_keys.map { |e| ":#{e}" }.join(", ")}", RED)
59+
display_unpermitted_keys = unpermitted_keys.map { |e| ":#{e}" }.join(", ")
60+
context = event.payload[:context].map { |k, v| "#{k}: #{v}" }.join(", ")
61+
color("Unpermitted parameter#{'s' if unpermitted_keys.size > 1}: #{display_unpermitted_keys}. Context: { #{context} }", RED)
6062
end
6163
end
6264

actionpack/lib/action_controller/metal/strong_parameters.rb

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,13 @@ def initialize # :nodoc:
106106
#
107107
# * +permit_all_parameters+ - If it's +true+, all the parameters will be
108108
# permitted by default. The default is +false+.
109-
# * +action_on_unpermitted_parameters+ - Allow to control the behavior when parameters
110-
# that are not explicitly permitted are found. The values can be +false+ to just filter them
111-
# out, <tt>:log</tt> to additionally write a message on the logger, or <tt>:raise</tt> to raise
112-
# ActionController::UnpermittedParameters exception. The default value is <tt>:log</tt>
113-
# in test and development environments, +false+ otherwise.
109+
# * +action_on_unpermitted_parameters+ - Controls behavior when parameters that are not explicitly
110+
# permitted are found. The default value is <tt>:log</tt> in test and development environments,
111+
# +false+ otherwise. The values can be:
112+
# * +false+ to take no action.
113+
# * <tt>:log</tt> to emit an <tt>ActiveSupport::Notifications.instrument</tt> event on the
114+
# <tt>unpermitted_parameters.action_controller</tt> topic and log at the DEBUG level.
115+
# * <tt>:raise</tt> to raise a <tt>ActionController::UnpermittedParameters</tt> exception.
114116
#
115117
# Examples:
116118
#
@@ -277,8 +279,9 @@ def nested_attribute?(key, value) # :nodoc:
277279
# params = ActionController::Parameters.new(name: "Francesco")
278280
# params.permitted? # => true
279281
# Person.new(params) # => #<Person id: nil, name: "Francesco">
280-
def initialize(parameters = {})
282+
def initialize(parameters = {}, logging_context = {})
281283
@parameters = parameters.with_indifferent_access
284+
@logging_context = logging_context
282285
@permitted = self.class.permit_all_parameters
283286
end
284287

@@ -968,7 +971,7 @@ def unpermitted_parameters!(params)
968971
case self.class.action_on_unpermitted_parameters
969972
when :log
970973
name = "unpermitted_parameters.action_controller"
971-
ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys)
974+
ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys, context: @logging_context)
972975
when :raise
973976
raise ActionController::UnpermittedParameters.new(unpermitted_keys)
974977
end
@@ -1184,7 +1187,15 @@ module StrongParameters
11841187
# Returns a new ActionController::Parameters object that
11851188
# has been instantiated with the <tt>request.parameters</tt>.
11861189
def params
1187-
@_params ||= Parameters.new(request.parameters)
1190+
@_params ||= begin
1191+
context = {
1192+
controller: self.class.name,
1193+
action: action_name,
1194+
request: request,
1195+
params: request.filtered_parameters
1196+
}
1197+
Parameters.new(request.parameters, context)
1198+
end
11881199
end
11891200

11901201
# Assigns the given +value+ to the +params+ hash. If +value+

actionpack/test/controller/parameters/log_on_unpermitted_params_test.rb

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,21 @@ def teardown
1313
end
1414

1515
test "logs on unexpected param" do
16-
params = ActionController::Parameters.new(
17-
book: { pages: 65 },
18-
fishing: "Turnips")
16+
request_params = { book: { pages: 65 }, fishing: "Turnips" }
17+
context = { "action" => "my_action", "controller" => "my_controller" }
18+
params = ActionController::Parameters.new(request_params, context)
1919

20-
assert_logged("Unpermitted parameter: :fishing") do
20+
assert_logged("Unpermitted parameter: :fishing. Context: { action: my_action, controller: my_controller }") do
2121
params.permit(book: [:pages])
2222
end
2323
end
2424

2525
test "logs on unexpected params" do
26-
params = ActionController::Parameters.new(
27-
book: { pages: 65 },
28-
fishing: "Turnips",
29-
car: "Mersedes")
26+
request_params = { book: { pages: 65 }, fishing: "Turnips", car: "Mersedes" }
27+
context = { "action" => "my_action", "controller" => "my_controller" }
28+
params = ActionController::Parameters.new(request_params, context)
3029

31-
assert_logged("Unpermitted parameters: :fishing, :car") do
30+
assert_logged("Unpermitted parameters: :fishing, :car. Context: { action: my_action, controller: my_controller }") do
3231
params.permit(book: [:pages])
3332
end
3433
end
@@ -37,7 +36,7 @@ def teardown
3736
params = ActionController::Parameters.new(
3837
book: { pages: 65, title: "Green Cats and where to find then." })
3938

40-
assert_logged("Unpermitted parameter: :title") do
39+
assert_logged("Unpermitted parameter: :title. Context: { }") do
4140
params.permit(book: [:pages])
4241
end
4342
end
@@ -46,7 +45,7 @@ def teardown
4645
params = ActionController::Parameters.new(
4746
book: { pages: 65, title: "Green Cats and where to find then.", author: "G. A. Dog" })
4847

49-
assert_logged("Unpermitted parameters: :title, :author") do
48+
assert_logged("Unpermitted parameters: :title, :author. Context: { }") do
5049
params.permit(book: [:pages])
5150
end
5251
end

guides/source/active_support_instrumentation.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,9 +280,10 @@ INFO. Additional keys may be added by the caller.
280280

281281
### unpermitted_parameters.action_controller
282282

283-
| Key | Value |
284-
| ------- | ---------------- |
285-
| `:keys` | Unpermitted keys |
283+
| Key | Value |
284+
| ------------- | --------------------------------------------------------------------- |
285+
| `:key` | The unpermitted keys |
286+
| `:context` | Hash with the following keys: :controller, :action, :params, :request |
286287

287288
Action Dispatch
288289
---------------

guides/source/configuring.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,10 @@ The schema dumper adds two additional configuration options:
526526
527527
* `config.action_controller.permit_all_parameters` sets all the parameters for mass assignment to be permitted by default. The default value is `false`.
528528
529-
* `config.action_controller.action_on_unpermitted_parameters` enables logging or raising an exception if parameters that are not explicitly permitted are found. Set to `:log` or `:raise` to enable. The default value is `:log` in development and test environments, and `false` in all other environments.
529+
* `config.action_controller.action_on_unpermitted_parameters` controls behavior when parameters that are not explicitly permitted are found. The default value is `:log` in test and development environments, `false` otherwise. The values can be:
530+
* `false` to take no action
531+
* `:log` to emit an `ActiveSupport::Notifications.instrument` event on the `unpermitted_parameters.action_controller` topic and log at the DEBUG level
532+
* `:raise` to raise a `ActionController::UnpermittedParameters` exception
530533
531534
* `config.action_controller.always_permitted_parameters` sets a list of permitted parameters that are permitted by default. The default values are `['controller', 'action']`.
532535

0 commit comments

Comments
 (0)