Skip to content
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

Merged
merged 1 commit into from
Apr 21, 2017

Conversation

rafaelfranca
Copy link
Member

Similar to #28734. The differences are:

  • to_h and to_hash only raises when config.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.

# 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
Copy link
Member

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.

Copy link
Member

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?

Copy link
Member Author

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

Copy link
Member Author

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
Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member

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?

Copy link
Member

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 %>
Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, that is true

Copy link
Contributor

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.

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra backtick

@rafaelfranca
Copy link
Member Author

Updated

Copy link
Contributor

@kaspth kaspth left a 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 😊

(`: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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stray backtick wraps "that`"

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`.
Copy link
Contributor

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?

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
Copy link
Contributor

@kaspth kaspth Apr 20, 2017

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.)

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
Copy link
Contributor

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:
Copy link
Contributor

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??

Copy link
Member Author

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
Copy link
Member

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?
Copy link
Member

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.

@rafaelfranca
Copy link
Member Author

Updated

Improve the upgrade path of Strong Parameters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants