aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
authorKasper Timm Hansen <kaspth@gmail.com>2016-08-02 14:54:25 +0200
committerKasper Timm Hansen <kaspth@gmail.com>2016-08-02 14:54:25 +0200
commit6eb978234cdce57e75c36a096fa76a634705c7c8 (patch)
tree028f76821c190c056f92a8f81a80d49f37cbe3f9 /actionpack
parent6b441559b1e4bfa080e99a9f55fb5e8f3ced4864 (diff)
downloadrails-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')
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb11
-rw-r--r--actionpack/test/controller/parameters/serialization_test.rb17
2 files changed, 24 insertions, 4 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
diff --git a/actionpack/test/controller/parameters/serialization_test.rb b/actionpack/test/controller/parameters/serialization_test.rb
index 5d389f5a4c..84193e304a 100644
--- a/actionpack/test/controller/parameters/serialization_test.rb
+++ b/actionpack/test/controller/parameters/serialization_test.rb
@@ -20,13 +20,26 @@ class ParametersSerializationTest < ActiveSupport::TestCase
assert_not roundtripped.permitted?
end
- test 'yaml backwardscompatible with hash inheriting parameters' do
- assert_equal ActionController::Parameters.new(key: :value), YAML.load(<<-end_of_yaml.strip_heredoc)
+ test 'yaml backwardscompatible with psych 2.0.8 format' do
+ params = YAML.load <<-end_of_yaml.strip_heredoc
+ --- !ruby/hash:ActionController::Parameters
+ key: :value
+ end_of_yaml
+
+ assert_equal :value, params[:key]
+ assert_not params.permitted?
+ end
+
+ test 'yaml backwardscompatible with psych 2.0.9+ format' do
+ params = YAML.load(<<-end_of_yaml.strip_heredoc)
--- !ruby/hash-with-ivars:ActionController::Parameters
elements:
key: :value
ivars:
:@permitted: false
end_of_yaml
+
+ assert_equal :value, params[:key]
+ assert_not params.permitted?
end
end