diff options
| author | Jon Leighton <j@jonathanleighton.com> | 2011-11-30 22:31:52 +0000 | 
|---|---|---|
| committer | Jon Leighton <j@jonathanleighton.com> | 2011-11-30 23:18:40 +0000 | 
| commit | 7895182d0fce11131024305f53d0cbb32817e65c (patch) | |
| tree | 5781756f8fdd6cabd552d32631433c656cc51cc9 /activerecord/lib/active_record/attribute_methods | |
| parent | 4f20eb5908895ac1f074cc1e2bc60f58e2d50a03 (diff) | |
| download | rails-7895182d0fce11131024305f53d0cbb32817e65c.tar.gz rails-7895182d0fce11131024305f53d0cbb32817e65c.tar.bz2 rails-7895182d0fce11131024305f53d0cbb32817e65c.zip  | |
omg computer science!
Implement a mini state machine for serialized attributes. This means we
do not have to deserialize the values upon initialization, which means
that if we never actually access the attribute, we never have to
deserialize it.
Diffstat (limited to 'activerecord/lib/active_record/attribute_methods')
| -rw-r--r-- | activerecord/lib/active_record/attribute_methods/serialization.rb | 52 | ||||
| -rw-r--r-- | activerecord/lib/active_record/attribute_methods/write.rb | 14 | 
2 files changed, 44 insertions, 22 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  | 
