Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Make serialized columns with explicit object_type return a new instan…

…ce of the object instead of nil
  • Loading branch information...
commit 351331fb343cdf17baa078943898ded6caff9d65 1 parent 080345b
@guillermo guillermo authored tenderlove committed
View
24 activerecord/lib/active_record/base.rb
@@ -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
View
2  activerecord/lib/active_record/coders/yaml_column.rb
@@ -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
View
19 activerecord/test/cases/base_test.rb
@@ -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)
View
5 activerecord/test/cases/coders/yaml_column_test.rb
@@ -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
Please sign in to comment.
Something went wrong with that request. Please try again.