Make serialized columns with explicit object_type return a new instance of the object instead of nil
This commit is contained in:
parent
080345baca
commit
351331fb34
@ -249,6 +249,17 @@ module ActiveRecord #:nodoc:
|
||||
# user = User.create(:preferences => %w( one two three ))
|
||||
# User.find(user.id).preferences # raises SerializationTypeMismatch
|
||||
#
|
||||
# When you specify a class option, the default value for that attribute will be a new
|
||||
# instance of that class.
|
||||
#
|
||||
# class User < ActiveRecord::Base
|
||||
# serialize :preferences, OpenStruct
|
||||
# end
|
||||
#
|
||||
# user = User.new
|
||||
# user.preferences.theme_color = "red"
|
||||
#
|
||||
#
|
||||
# == Single table inheritance
|
||||
#
|
||||
# Active Record allows inheritance by storing the name of the class in a column that by
|
||||
@ -1409,6 +1420,7 @@ def initialize(attributes = nil)
|
||||
@changed_attributes = {}
|
||||
|
||||
ensure_proper_type
|
||||
set_serialized_attributes
|
||||
|
||||
populate_with_current_scope_attributes
|
||||
self.attributes = attributes unless attributes.nil?
|
||||
@ -1447,10 +1459,7 @@ def encode_with(coder)
|
||||
def init_with(coder)
|
||||
@attributes = coder['attributes']
|
||||
|
||||
(@attributes.keys & self.class.serialized_attributes.keys).each do |key|
|
||||
coder = self.class.serialized_attributes[key]
|
||||
@attributes[key] = coder.load @attributes[key]
|
||||
end
|
||||
set_serialized_attributes
|
||||
|
||||
@attributes_cache, @previously_changed, @changed_attributes = {}, {}, {}
|
||||
@association_cache = {}
|
||||
@ -1461,6 +1470,13 @@ def init_with(coder)
|
||||
run_callbacks :initialize
|
||||
end
|
||||
|
||||
def set_serialized_attributes
|
||||
(@attributes.keys & self.class.serialized_attributes.keys).each do |key|
|
||||
coder = self.class.serialized_attributes[key]
|
||||
@attributes[key] = coder.load @attributes[key]
|
||||
end
|
||||
end
|
||||
|
||||
# Specifies how the record is dumped by +Marshal+.
|
||||
#
|
||||
# +_dump+ emits a marshalled hash which has been passed to +encode_with+. Override this
|
||||
|
@ -19,6 +19,7 @@ def dump(obj)
|
||||
end
|
||||
|
||||
def load(yaml)
|
||||
return object_class.new if object_class != Object && yaml.nil?
|
||||
return yaml unless yaml.is_a?(String) && yaml =~ /^---/
|
||||
begin
|
||||
obj = YAML.load(yaml)
|
||||
@ -27,6 +28,7 @@ def load(yaml)
|
||||
raise SerializationTypeMismatch,
|
||||
"Attribute was supposed to be a #{object_class}, but was a #{obj.class}"
|
||||
end
|
||||
obj ||= object_class.new if object_class != Object
|
||||
|
||||
obj
|
||||
rescue *RESCUE_ERRORS
|
||||
|
@ -1002,6 +1002,25 @@ def test_serialized_attribute_with_class_constraint
|
||||
Topic.serialize(:content)
|
||||
end
|
||||
|
||||
def test_serialized_default_class
|
||||
Topic.serialize(:content, Hash)
|
||||
topic = Topic.new
|
||||
assert_equal Hash, topic.content.class
|
||||
assert_equal Hash, topic.read_attribute(:content).class
|
||||
topic.content["beer"] = "MadridRb"
|
||||
assert topic.save
|
||||
topic.reload
|
||||
assert_equal Hash, topic.content.class
|
||||
assert_equal "MadridRb", topic.content["beer"]
|
||||
ensure
|
||||
Topic.serialize(:content)
|
||||
end
|
||||
|
||||
def test_serialized_no_default_class_for_object
|
||||
topic = Topic.new
|
||||
assert_nil topic.content
|
||||
end
|
||||
|
||||
def test_serialized_boolean_value_true
|
||||
Topic.serialize(:content)
|
||||
topic = Topic.new(:content => true)
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
require "cases/helper"
|
||||
|
||||
module ActiveRecord
|
||||
@ -20,9 +21,9 @@ def test_nil_is_ok
|
||||
assert_nil coder.load "--- "
|
||||
end
|
||||
|
||||
def test_nil_is_ok_with_different_class
|
||||
def test_returns_new_with_different_class
|
||||
coder = YAMLColumn.new SerializationTypeMismatch
|
||||
assert_nil coder.load "--- "
|
||||
assert_equal SerializationTypeMismatch, coder.load("--- ").class
|
||||
end
|
||||
|
||||
def test_returns_string_unless_starts_with_dash
|
||||
|
Loading…
Reference in New Issue
Block a user