diff options
author | Kasper Timm Hansen <kaspth@gmail.com> | 2016-08-02 14:54:25 +0200 |
---|---|---|
committer | Kasper Timm Hansen <kaspth@gmail.com> | 2016-08-02 14:54:25 +0200 |
commit | 6eb978234cdce57e75c36a096fa76a634705c7c8 (patch) | |
tree | 028f76821c190c056f92a8f81a80d49f37cbe3f9 /actionpack/lib/action_controller/metal/strong_parameters.rb | |
parent | 6b441559b1e4bfa080e99a9f55fb5e8f3ced4864 (diff) | |
download | rails-6eb978234cdce57e75c36a096fa76a634705c7c8.tar.gz rails-6eb978234cdce57e75c36a096fa76a634705c7c8.tar.bz2 rails-6eb978234cdce57e75c36a096fa76a634705c7c8.zip |
Let Psych 2.0.9+ deserialize 2.0.8 serialized parameters.
If we were to serialize an `ActionController::Parameters` on Psych 2.0.8, we'd get:
```yaml
--- !ruby/hash:ActionController::Parameters
key: :value
```
Because 2.0.8 didn't store instance variables, while 2.0.9 did:
https://github.com/tenderlove/psych/commit/8f84ad0fc711a82a1040def861cb121e8985fd4c
That, coupled with 2.0.8 calling `new` instead of `allocate` meant parameters was
deserialized just fine:
https://github.com/tenderlove/psych/commit/af308f8307899cb9e1c0fffea4bce3110a1c3926
However, if users have 2.0.8 serialized parameters, then upgrade to Psych 2.0.9+ and
Rails 5, it would start to blow up because `initialize` will never be called, and thus
`@parameters` will never be assigned. Hello, `NoMethodErrors` on `NilClass`! :)
To fix this we register another variant of the previous serialization format and take
it into account in `init_with`.
I've tested this in our app and previously raising code now deserializes like a champ.
I'm unsure how to test this in our suite because we use Psych 2.0.8 and don't know how
to make us use 2.0.9+ for just one test.
Diffstat (limited to 'actionpack/lib/action_controller/metal/strong_parameters.rb')
-rw-r--r-- | actionpack/lib/action_controller/metal/strong_parameters.rb | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index 98624ba103..d2db982a6e 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -12,7 +12,10 @@ require 'yaml' # Wire up YAML format compatibility with Rails 4.2. Makes the YAML parser call # `init_with` when it encounters `!ruby/hash-with-ivars:ActionController::Parameters`, # instead of trying to parse it as a regular hash subclass. +# Second `load_tags` is for compatibility with Psych prior to 2.0.9 where hashes +# were dumped without instance variables. YAML.load_tags['!ruby/hash-with-ivars:ActionController::Parameters'] = 'ActionController::Parameters' +YAML.load_tags['!ruby/hash:ActionController::Parameters'] = 'ActionController::Parameters' module ActionController # Raised when a required parameter is missing. @@ -599,14 +602,18 @@ module ActionController def init_with(coder) # :nodoc: if coder.map['elements'] - # YAML's Hash subclass format from Rails 4.2, where keys and values + # YAML 2.0.9's Hash subclass format from Rails 4.2, where keys and values # were stored under an elements hash and `permitted` within an ivars hash. @parameters = coder.map['elements'].with_indifferent_access @permitted = coder.map['ivars'][:@permitted] - else + elsif coder.map['parameters'] # YAML's Object format. Only needed because of the format # backwardscompability above, otherwise equivalent to YAML's initialization. @parameters, @permitted = coder.map['parameters'], coder.map['permitted'] + else + # YAML 2.0.8's format where hash instance variables weren't stored. + @parameters = coder.map.with_indifferent_access + @permitted = false end end |