From 1f633c78ea7ff13a8f35d64e8172b774dd662667 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 17 Aug 2012 18:40:39 +0100 Subject: Pull more serialize code into a lazy included module --- .../attribute_methods/serialization.rb | 123 +++++++++++---------- 1 file changed, 63 insertions(+), 60 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb index e6f848df22..33d7cc7f34 100644 --- a/activerecord/lib/active_record/attribute_methods/serialization.rb +++ b/activerecord/lib/active_record/attribute_methods/serialization.rb @@ -10,6 +10,37 @@ module ActiveRecord self.serialized_attributes = {} 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. + # The serialization is done through YAML. If +class_name+ is specified, the serialized object must be of that + # class on retrieval or SerializationTypeMismatch will be raised. + # + # ==== Parameters + # + # * +attr_name+ - The field name that should be serialized. + # * +class_name+ - Optional, class name that the object type should be equal to. + # + # ==== Example + # # Serialize a preferences attribute + # class User < ActiveRecord::Base + # serialize :preferences + # end + def serialize(attr_name, class_name = Object) + include Behavior + + coder = if [:load, :dump].all? { |x| class_name.respond_to?(x) } + class_name + else + Coders::YAMLColumn.new(class_name) + end + + # merge new serialized attribute and create new hash to ensure that each class in inheritance hierarchy + # has its own hash of own serialized attributes + self.serialized_attributes = serialized_attributes.merge(attr_name.to_s => coder) + end + end + class Type # :nodoc: def initialize(column) @column = column @@ -45,77 +76,49 @@ module ActiveRecord end # This is only added to the model when serialize is called, which - # ensures we do not make model instantiation slower when - # serialization is not used. - module InitializeAttributes #:nodoc: - def initialize_attributes(attributes, options = {}) - serialized = (options.delete(:serialized) { true }) ? :serialized : :unserialized - super(attributes, options) - - serialized_attributes.each do |key, coder| - if attributes.key?(key) - attributes[key] = Attribute.new(coder, attributes[key], serialized) + # ensures we do not make things slower when serialization is not used. + module Behavior #:nodoc: + extend ActiveSupport::Concern + + module ClassMethods + def initialize_attributes(attributes, options = {}) + serialized = (options.delete(:serialized) { true }) ? :serialized : :unserialized + super(attributes, options) + + serialized_attributes.each do |key, coder| + if attributes.key?(key) + attributes[key] = Attribute.new(coder, attributes[key], serialized) + end end - end - attributes - 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. - # The serialization is done through YAML. If +class_name+ is specified, the serialized object must be of that - # class on retrieval or SerializationTypeMismatch will be raised. - # - # ==== Parameters - # - # * +attr_name+ - The field name that should be serialized. - # * +class_name+ - Optional, class name that the object type should be equal to. - # - # ==== Example - # # Serialize a preferences attribute - # class User < ActiveRecord::Base - # serialize :preferences - # end - def serialize(attr_name, class_name = Object) - extend InitializeAttributes + attributes + end - coder = if [:load, :dump].all? { |x| class_name.respond_to?(x) } - class_name - else - Coders::YAMLColumn.new(class_name) - end + private - # merge new serialized attribute and create new hash to ensure that each class in inheritance hierarchy - # has its own hash of own serialized attributes - self.serialized_attributes = serialized_attributes.merge(attr_name.to_s => coder) + def attribute_cast_code(attr_name) + if serialized_attributes.include?(attr_name) + "v.unserialized_value" + else + super + end + end end - private - - def attribute_cast_code(attr_name) - if serialized_attributes.include?(attr_name) - "v.unserialized_value" + def type_cast_attribute_for_write(column, value) + if column && coder = self.class.serialized_attributes[column.name] + Attribute.new(coder, value, :unserialized) else super end end - end - - def type_cast_attribute_for_write(column, value) - if column && coder = self.class.serialized_attributes[column.name] - Attribute.new(coder, value, :unserialized) - else - super - end - end - def read_attribute_before_type_cast(attr_name) - if serialized_attributes.include?(attr_name) - super.unserialized_value - else - super + def read_attribute_before_type_cast(attr_name) + if serialized_attributes.include?(attr_name) + super.unserialized_value + else + super + end end end end -- cgit v1.2.3