From be79632b96d6fe6b844c99561ce96f540e98cae0 Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Mon, 12 Nov 2012 14:33:20 +0100 Subject: [PATCH] backport #8185, `#as_json` isolates options when encoding a hash. Setting options in a custom `#as_json` method had side effects. Modifications of the `options` hash leaked outside and influenced the conversion of other objects contained in the hash. Conflicts: activesupport/CHANGELOG.md --- activesupport/CHANGELOG.md | 5 +++++ .../lib/active_support/json/encoding.rb | 2 +- activesupport/test/json/encoding_test.rb | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 749441e3436d5..d15c341b9f7c9 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,5 +1,10 @@ ## Rails 3.2.10 (unreleased) +* `#as_json` isolates options when encoding a hash. [Backport #8185] + Fix #8182 + + *Yves Senn* + * Handle the possible Permission Denied errors atomic.rb might trigger due to its chown and chmod calls. [Backport #8027] diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb index 91e4f07c6c134..bd2f909ca9539 100644 --- a/activesupport/lib/active_support/json/encoding.rb +++ b/activesupport/lib/active_support/json/encoding.rb @@ -61,7 +61,7 @@ def options_for(value) # hashes and arrays need to get encoder in the options, so that they can detect circular references options.merge(:encoder => self) else - options + options.dup end end diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb index a9590f164f9fe..6cbf956be234b 100644 --- a/activesupport/test/json/encoding_test.rb +++ b/activesupport/test/json/encoding_test.rb @@ -22,6 +22,15 @@ def as_json(options) end end + class CustomWithOptions + attr_accessor :foo, :bar + + def as_json(options={}) + options[:only] = %w(foo bar) + super(options) + end + end + TrueTests = [[ true, %(true) ]] FalseTests = [[ false, %(false) ]] NilTests = [[ nil, %(null) ]] @@ -239,6 +248,15 @@ def test_enumerable_should_pass_encoding_options_to_children_in_to_json assert_equal(%([{"address":{"city":"London"}},{"address":{"city":"Paris"}}]), json) end + def test_to_json_should_not_keep_options_around + f = CustomWithOptions.new + f.foo = "hello" + f.bar = "world" + + hash = {"foo" => f, "other_hash" => {"foo" => "other_foo", "test" => "other_test"}} + assert_equal(%({"foo":{"foo":"hello","bar":"world"},"other_hash":{"foo":"other_foo","test":"other_test"}}), hash.to_json) + end + def test_struct_encoding Struct.new('UserNameAndEmail', :name, :email) Struct.new('UserNameAndDate', :name, :date)