aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuillermo Álvarez <guillermo@cientifico.net>2011-02-03 00:26:39 +0100
committerAaron Patterson <aaron.patterson@gmail.com>2011-02-03 09:08:45 -0800
commit351331fb343cdf17baa078943898ded6caff9d65 (patch)
tree8b57684788395cbe899a27c24f51a990eb416584
parent080345baca1076a9788dff4803153600aec31f86 (diff)
downloadrails-351331fb343cdf17baa078943898ded6caff9d65.tar.gz
rails-351331fb343cdf17baa078943898ded6caff9d65.tar.bz2
rails-351331fb343cdf17baa078943898ded6caff9d65.zip
Make serialized columns with explicit object_type return a new instance of the object instead of nil
-rw-r--r--activerecord/lib/active_record/base.rb24
-rw-r--r--activerecord/lib/active_record/coders/yaml_column.rb2
-rw-r--r--activerecord/test/cases/base_test.rb19
-rw-r--r--activerecord/test/cases/coders/yaml_column_test.rb5
4 files changed, 44 insertions, 6 deletions
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 0941700803..e0957e2849 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/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 @@ MSG
@changed_attributes = {}
ensure_proper_type
+ set_serialized_attributes
populate_with_current_scope_attributes
self.attributes = attributes unless attributes.nil?
@@ -1447,10 +1459,7 @@ MSG
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 @@ MSG
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
diff --git a/activerecord/lib/active_record/coders/yaml_column.rb b/activerecord/lib/active_record/coders/yaml_column.rb
index fcecc11aba..fb59d9fb07 100644
--- a/activerecord/lib/active_record/coders/yaml_column.rb
+++ b/activerecord/lib/active_record/coders/yaml_column.rb
@@ -19,6 +19,7 @@ module ActiveRecord
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 @@ module ActiveRecord
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
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 5cbc52732b..a255c07957 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1002,6 +1002,25 @@ class BasicsTest < ActiveRecord::TestCase
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)
diff --git a/activerecord/test/cases/coders/yaml_column_test.rb b/activerecord/test/cases/coders/yaml_column_test.rb
index f85f11b57f..c7dcc21809 100644
--- a/activerecord/test/cases/coders/yaml_column_test.rb
+++ b/activerecord/test/cases/coders/yaml_column_test.rb
@@ -1,3 +1,4 @@
+
require "cases/helper"
module ActiveRecord
@@ -20,9 +21,9 @@ module ActiveRecord
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