1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Fix backward compatibility with stored Hash values. Wrap coders to convert serialized values to indifferent access.

This commit is contained in:
Jeremy Kemper 2012-05-30 23:18:08 -07:00
parent 9a30d82d45
commit d5354af114
3 changed files with 51 additions and 15 deletions

View file

@ -38,7 +38,7 @@ module ActiveRecord
module ClassMethods module ClassMethods
def store(store_attribute, options = {}) def store(store_attribute, options = {})
serialize store_attribute, options.fetch(:coder, ActiveSupport::HashWithIndifferentAccess) serialize store_attribute, IndifferentCoder.new(options[:coder])
store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors
end end
@ -47,7 +47,7 @@ module ActiveRecord
define_method("#{key}=") do |value| define_method("#{key}=") do |value|
initialize_store_attribute(store_attribute) initialize_store_attribute(store_attribute)
send(store_attribute)[key] = value send(store_attribute)[key] = value
send("#{store_attribute}_will_change!") send :"#{store_attribute}_will_change!"
end end
define_method(key) do define_method(key) do
@ -71,5 +71,35 @@ module ActiveRecord
send :"#{store_attribute}=", ActiveSupport::HashWithIndifferentAccess.new send :"#{store_attribute}=", ActiveSupport::HashWithIndifferentAccess.new
end end
end end
class IndifferentCoder
def initialize(coder_or_class_name)
@coder =
if coder_or_class_name.respond_to?(:load) && coder_or_class_name.respond_to?(:dump)
coder_or_class_name
else
ActiveRecord::Coders::YAMLColumn.new(coder_or_class_name || Object)
end
end
def dump(obj)
@coder.dump self.class.as_indifferent_hash(obj)
end
def load(yaml)
self.class.as_indifferent_hash @coder.load(yaml)
end
def self.as_indifferent_hash(obj)
case obj
when ActiveSupport::HashWithIndifferentAccess
obj
when Hash
obj.with_indifferent_access
else
HashWithIndifferentAccess.new
end
end
end
end end
end end

View file

@ -3,8 +3,10 @@ require 'models/admin'
require 'models/admin/user' require 'models/admin/user'
class StoreTest < ActiveRecord::TestCase class StoreTest < ActiveRecord::TestCase
fixtures :'admin/users'
setup do setup do
@john = Admin::User.create(:name => 'John Doe', :color => 'black', :remember_login => true, :height => 'tall', :is_a_good_guy => true) @john = Admin::User.create!(:name => 'John Doe', :color => 'black', :remember_login => true, :height => 'tall', :is_a_good_guy => true)
end end
test "reading store attributes through accessors" do test "reading store attributes through accessors" do
@ -52,18 +54,19 @@ class StoreTest < ActiveRecord::TestCase
end end
test "convert store attributes from Hash to HashWithIndifferentAccess saving the data and access attributes indifferently" do test "convert store attributes from Hash to HashWithIndifferentAccess saving the data and access attributes indifferently" do
@john.json_data = { :height => 'tall', 'weight' => 'heavy' } user = Admin::User.find_by_name('Jamis')
assert_equal true, @john.json_data.instance_of?(Hash) assert_equal 'symbol', user.settings[:symbol]
assert_equal 'tall', @john.json_data[:height] assert_equal 'symbol', user.settings['symbol']
assert_equal nil, @john.json_data['height'] assert_equal 'string', user.settings[:string]
assert_equal nil, @john.json_data[:weight] assert_equal 'string', user.settings['string']
assert_equal 'heavy', @john.json_data['weight'] assert_equal true, user.settings.instance_of?(ActiveSupport::HashWithIndifferentAccess)
@john.height = 'low'
assert_equal true, @john.json_data.instance_of?(HashWithIndifferentAccess) user.height = 'low'
assert_equal 'low', @john.json_data[:height] assert_equal 'symbol', user.settings[:symbol]
assert_equal 'low', @john.json_data['height'] assert_equal 'symbol', user.settings['symbol']
assert_equal 'heavy', @john.json_data[:weight] assert_equal 'string', user.settings[:string]
assert_equal 'heavy', @john.json_data['weight'] assert_equal 'string', user.settings['string']
assert_equal true, user.settings.instance_of?(ActiveSupport::HashWithIndifferentAccess)
end end
test "convert store attributes from any format other than Hash or HashWithIndifferent access losing the data" do test "convert store attributes from any format other than Hash or HashWithIndifferent access losing the data" do

View file

@ -5,3 +5,6 @@ david:
jamis: jamis:
name: Jamis name: Jamis
account: signals37 account: signals37
settings:
:symbol: symbol
string: string