diff options
Diffstat (limited to 'activerecord/lib/active_record')
-rw-r--r-- | activerecord/lib/active_record/attribute_methods/serialization.rb | 52 | ||||
-rw-r--r-- | activerecord/lib/active_record/attribute_methods/write.rb | 14 | ||||
-rw-r--r-- | activerecord/lib/active_record/base.rb | 4 |
3 files changed, 46 insertions, 24 deletions
diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb index ac65ef94f9..bc7e9d7a94 100644 --- a/activerecord/lib/active_record/attribute_methods/serialization.rb +++ b/activerecord/lib/active_record/attribute_methods/serialization.rb @@ -10,6 +10,26 @@ module ActiveRecord self.serialized_attributes = {} end + class Attribute < Struct.new(:coder, :value, :state) + def unserialized_value + state == :serialized ? unserialize : value + end + + def serialized_value + state == :unserialized ? serialize : value + end + + def unserialize + self.state = :unserialized + self.value = coder.load(value) + end + + def serialize + self.state = :serialized + self.value = coder.dump(value) + end + end + module ClassMethods # If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, # then specify the name of that attribute using this method and it will be handled automatically. @@ -42,7 +62,7 @@ module ActiveRecord if serialized_attributes.include?(attr_name) generated_attribute_methods.module_eval(<<-CODE, __FILE__, __LINE__) def _#{attr_name} - @attributes_cache['#{attr_name}'] ||= @attributes['#{attr_name}'] + @attributes['#{attr_name}'].unserialized_value end alias #{attr_name} _#{attr_name} CODE @@ -50,31 +70,27 @@ module ActiveRecord super end end - - def cacheable_column?(column) - serialized_attributes.include?(column.name) || super - end end def set_serialized_attributes - sattrs = self.class.serialized_attributes - - sattrs.each do |key, coder| - @attributes[key] = coder.load @attributes[key] if @attributes.key?(key) + self.class.serialized_attributes.each do |key, coder| + if @attributes.key?(key) + @attributes[key] = Attribute.new(coder, @attributes[key], :serialized) + end end end def type_cast_attribute(column) - coder = self.class.serialized_attributes[column.name] - - if column.text? && coder - unserialized_object = coder.load(@attributes[column.name]) + if column.text? && self.class.serialized_attributes.include?(column.name) + @attributes[column.name].unserialized_value + else + super + end + end - if @attributes.frozen? - unserialized_object - else - @attributes[column.name] = unserialized_object - end + def type_cast_attribute_for_write(column, attr_name, value) + if column && coder = self.class.serialized_attributes[column.name] + Attribute.new(coder, value, :unserialized) else super end diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb index b605c09889..650156f3cf 100644 --- a/activerecord/lib/active_record/attribute_methods/write.rb +++ b/activerecord/lib/active_record/attribute_methods/write.rb @@ -28,10 +28,8 @@ module ActiveRecord @attributes_cache.delete(attr_name) column = column_for_attribute(attr_name) - if column && column.number? - @attributes[attr_name] = convert_number_column_value(value) - elsif column || @attributes.has_key?(attr_name) - @attributes[attr_name] = value + if column || @attributes.has_key?(attr_name) + @attributes[attr_name] = type_cast_attribute_for_write(column, attr_name, value) else raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{attr_name}'" end @@ -43,6 +41,14 @@ module ActiveRecord def attribute=(attribute_name, value) write_attribute(attribute_name, value) end + + def type_cast_attribute_for_write(column, attr_name, value) + if column && column.number? + convert_number_column_value(value) + else + value + end + end end end end diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 2c7cb09d7a..ee2833c5dc 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -2003,8 +2003,8 @@ MSG if include_readonly_attributes || (!include_readonly_attributes && !self.class.readonly_attributes.include?(name)) - value = if coder = klass.serialized_attributes[name] - coder.dump @attributes[name] + value = if klass.serialized_attributes.include?(name) + @attributes[name].serialized_value else # FIXME: we need @attributes to be used consistently. # If the values stored in @attributes were already type |