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
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
end
@ -47,7 +47,7 @@ module ActiveRecord
define_method("#{key}=") do |value|
initialize_store_attribute(store_attribute)
send(store_attribute)[key] = value
send("#{store_attribute}_will_change!")
send :"#{store_attribute}_will_change!"
end
define_method(key) do
@ -71,5 +71,35 @@ module ActiveRecord
send :"#{store_attribute}=", ActiveSupport::HashWithIndifferentAccess.new
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

View file

@ -3,8 +3,10 @@ require 'models/admin'
require 'models/admin/user'
class StoreTest < ActiveRecord::TestCase
fixtures :'admin/users'
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
test "reading store attributes through accessors" do
@ -52,18 +54,19 @@ class StoreTest < ActiveRecord::TestCase
end
test "convert store attributes from Hash to HashWithIndifferentAccess saving the data and access attributes indifferently" do
@john.json_data = { :height => 'tall', 'weight' => 'heavy' }
assert_equal true, @john.json_data.instance_of?(Hash)
assert_equal 'tall', @john.json_data[:height]
assert_equal nil, @john.json_data['height']
assert_equal nil, @john.json_data[:weight]
assert_equal 'heavy', @john.json_data['weight']
@john.height = 'low'
assert_equal true, @john.json_data.instance_of?(HashWithIndifferentAccess)
assert_equal 'low', @john.json_data[:height]
assert_equal 'low', @john.json_data['height']
assert_equal 'heavy', @john.json_data[:weight]
assert_equal 'heavy', @john.json_data['weight']
user = Admin::User.find_by_name('Jamis')
assert_equal 'symbol', user.settings[:symbol]
assert_equal 'symbol', user.settings['symbol']
assert_equal 'string', user.settings[:string]
assert_equal 'string', user.settings['string']
assert_equal true, user.settings.instance_of?(ActiveSupport::HashWithIndifferentAccess)
user.height = 'low'
assert_equal 'symbol', user.settings[:symbol]
assert_equal 'symbol', user.settings['symbol']
assert_equal 'string', user.settings[:string]
assert_equal 'string', user.settings['string']
assert_equal true, user.settings.instance_of?(ActiveSupport::HashWithIndifferentAccess)
end
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:
name: Jamis
account: signals37
settings:
:symbol: symbol
string: string