-
Notifications
You must be signed in to change notification settings - Fork 21.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve the upgrade path of Strong Parameters in 5-0-stable #28803
Conversation
# params[:key] # => "value" | ||
# params["key"] # => "value" | ||
class Parameters | ||
cattr_accessor :permit_all_parameters, instance_accessor: false | ||
cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false | ||
cattr_accessor :raise_on_unpermitted_parameters, instance_accessor: false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be unfiltered
? As is, it sounds confusingly overlapped with action_on_unpermitted_parameters
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to define & deprecate this config value in 5.1, for people who upgrade from a 5.0 version that includes it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. I was going to do that as soon we decide a name for the config
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. I'll change to unfiltered.
if self.class.raise_on_unpermitted_parameters | ||
to_h.to_hash | ||
else | ||
@parameters.to_hash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm tempted to make this do something different (e.g., always to_h.to_hash
).
My worry here is that this is not what it's currently/previously been doing in 5.0: the deprecation warning is going away, and respond_to?(:to_hash)
is becoming true. That latter part seems particularly significant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have hoping that the upgrade path to those who are already seeing the deprecation of to_hash
would be easier if we keep the same behavior when the configuration is disabled. Always doing to_h.to_hash
would return an empty hash now if the config is false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah.. I actually meant "what to_h.to_hash would do if the config were enabled", but that [by design] isn't compatible either.
At minimum I think we should keep a deprecation here: we can't deprecate to_h
with the config disabled, because we can't deprecate in a point release... but we can deprecate to_hash
with the config disabled, because it's already showing a deprecation warning: we'd just be changing the message and thus the advice (to "[read about and then] turn on this config").
I'm still worried that even with that, as soon as respond_to?(:to_hash)
becomes true, a lot of code will start treating this object differently (calling to_hash
where it currently does not). Maybe we should special-case :to_hash
in respond_to?
, and lie about it when the config setting is off?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which reminds me.. maybe as part of this PR, or maybe separately, we should fix (implement) respond_to_missing?
.
@@ -7,6 +7,8 @@ | |||
# | |||
<%- end -%> | |||
# Read the Guide for Upgrading Ruby on Rails for more info on each option. | |||
|
|||
Rails.application.config.raise_on_unpermitted_parameters = <%= options[:update] ? false : true %> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be true
for update too. This template is for upgrading 4.2 applications: we're only worried about keeping the existing behaviour for applications already on 5.0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, that is true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain again why this should be true
when running rails app:update
right after upgrading from Rails 4.2?
From the comment above, that means I am supposed to flip it to false
after I have made sure it works with false
. But that doesn't make sense.
actionpack/CHANGELOG.md
Outdated
in a unpermitted parameter. Now we delegate to `#to_h` that already raise an error when | ||
the Parameters instance is not permitted. | ||
|
||
This also fix a bug when using ``#to_query` in a hash that contains a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra backtick
c88c596
to
7f45a1a
Compare
Updated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some minor comments, but overall great 😊
actionpack/CHANGELOG.md
Outdated
(`:controller` and `:action` by default). | ||
|
||
The previous behavior was dangerous because in order to get the attributes users | ||
usually fallback to use `to_unsafe_h that` could potentially introduce security issues. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stray backtick wraps "that`"
actionpack/CHANGELOG.md
Outdated
requiring the users to change their implementation. | ||
|
||
This method will return a `Hash` instead of a `HashWithIndefirentAccess` to mimic the | ||
same implementation of `HashWithIndefirentAccess#to_hash`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we expand this to ActiveSupport::HashWithIndifferentAccess
since Action Controller isn't the namespace here?
actionpack/CHANGELOG.md
Outdated
Now methods that implicit convert objects to a hash will be able to work without | ||
requiring the users to change their implementation. | ||
|
||
This method will return a `Hash` instead of a `HashWithIndefirentAccess` to mimic the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious if we call symbolize_keys
in to_hash
would strong parameters basically work as keyword arguments? E.g. being able to do this would be sweet:
def hello(a:, d:)
end
hello(ActionController::Parameters.new(a: :c, d: :c))
hello(params) # …or more likely.
(And I think it would also fix the warts in the new resolve
and direct
API around parameters.)
actionpack/CHANGELOG.md
Outdated
This method will return a `Hash` instead of a `HashWithIndefirentAccess` to mimic the | ||
same implementation of `HashWithIndefirentAccess#to_hash`. | ||
|
||
This method will raise on unpermitted Parameters if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we say unfiltered here as well?
@@ -718,7 +795,15 @@ def method_missing(method_sym, *args, &block) | |||
end | |||
end | |||
|
|||
# Returns duplicate of object including all parameters | |||
def respond_to?(name, include_all = false) # :nodoc: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be respond_to_missing?
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can't be respond_to_missing?
because to_hash
is implemented and respond_to?
would return true
without calling respond_to_missing?
a security vulnerability in your app that can be exploited. Instead, | ||
consider enabling `config.action_controller.raise_on_unfiltered_parameters` and filtering | ||
the `ActionController::Parameters`. | ||
DEPRECATE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to_hash unexpectedly ignores parameter filtering, and will change to enforce it in Rails 5.1. Enable raise_on_unfiltered_parameters to respect parameter filtering, which is the default in new applications. For the existing deprecated behaviour, call to_unsafe_h instead.
Maybe? The "will be removed" phrasing seems particularly awkward when it's not really going away, per se.
if self.class.raise_on_unfiltered_parameters | ||
to_h.to_hash | ||
else | ||
unless permitted? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should keep the message regardless of whether it's permitted?
. It was there before, and using a non-filtering to_hash
is arguably worse if you think you've applied filtering.
Updated |
Improve the upgrade path of Strong Parameters
7f45a1a
to
458d8d2
Compare
Similar to #28734. The differences are:
to_h
andto_hash
only raises whenconfig.action_controller.raise_on_unpermitted_parameters
is true (default to false in existing application and true in new applications).The places where it was already raising are not reusing the
to_h
implementation.