提交 5d2ee966 编写于 作者: R Rafael Mendonça França

Merge pull request #15412 from sgrif/sg-serialized-type-cast-for-write

Move `type_cast_for_write` behavior over to the serialized type object
......@@ -62,7 +62,7 @@ def serialize(attr_name, class_name_or_coder = Object)
if type.serialized?
type = type.subtype
end
property attr_name, ActiveRecord::Type::Serialized.new(type)
property attr_name, Type::Serialized.new(type, coder)
# merge new serialized attribute and create new hash to ensure that each class in inheritance hierarchy
# has its own hash of own serialized attributes
......@@ -70,25 +70,6 @@ def serialize(attr_name, class_name_or_coder = Object)
end
end
class Attribute < Struct.new(:coder, :value, :state) # :nodoc:
def unserialized_value(v = value)
state == :serialized ? unserialize(v) : value
end
def serialized_value
state == :unserialized ? serialize : value
end
def unserialize(v)
self.state = :unserialized
self.value = coder.load(v)
end
def serialize
self.state = :serialized
self.value = coder.dump(value)
end
end
# This is only added to the model when serialize is called, which
# ensures we do not make things slower when serialization is not used.
......@@ -102,7 +83,7 @@ def initialize_attributes(attributes, options = {})
serialized_attributes.each do |key, coder|
if attributes.key?(key)
attributes[key] = Attribute.new(coder, attributes[key], serialized)
attributes[key] = Type::Serialized::Attribute.new(coder, attributes[key], serialized)
end
end
......@@ -118,22 +99,6 @@ def keys_for_partial_write
super | (attributes.keys & self.class.serialized_attributes.keys)
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 raw_type_cast_attribute_for_write(column, value)
if column && coder = self.class.serialized_attributes[column.name]
Attribute.new(coder, value, :serialized)
else
super
end
end
def _field_changed?(attr, old, value)
if self.class.serialized_attributes.include?(attr)
old != value
......
......@@ -55,11 +55,11 @@ def __temp__#{safe_name}=(value)
# specified +value+. Empty strings for fixnum and float columns are
# turned into +nil+.
def write_attribute(attr_name, value)
write_attribute_with_type_cast(attr_name, value, :type_cast_attribute_for_write)
write_attribute_with_type_cast(attr_name, value, :type_cast_for_write)
end
def raw_write_attribute(attr_name, value)
write_attribute_with_type_cast(attr_name, value, :raw_type_cast_attribute_for_write)
write_attribute_with_type_cast(attr_name, value, :raw_type_cast_for_write)
end
private
......@@ -68,13 +68,6 @@ def attribute=(attribute_name, value)
write_attribute(attribute_name, value)
end
def type_cast_attribute_for_write(column, value)
return value unless column
column.type_cast_for_write value
end
alias_method :raw_type_cast_attribute_for_write, :type_cast_attribute_for_write
def write_attribute_with_type_cast(attr_name, value, type_cast_method)
attr_name = attr_name.to_s
attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key
......@@ -87,8 +80,10 @@ def write_attribute_with_type_cast(attr_name, value, type_cast_method)
@attributes_cache[attr_name] = value
end
if column || @attributes.has_key?(attr_name)
@attributes[attr_name] = send(type_cast_method, column, value)
if column
@attributes[attr_name] = column.public_send(type_cast_method, value)
elsif @attributes.has_key?(attr_name)
@attributes[attr_name] = value
else
raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{attr_name}'"
end
......
......@@ -17,7 +17,7 @@ module Format
delegate :type, :precision, :scale, :limit, :klass, :accessor,
:text?, :number?, :binary?, :serialized?,
:type_cast, :type_cast_for_write, :type_cast_for_database,
:type_cast, :type_cast_for_write, :raw_type_cast_for_write, :type_cast_for_database,
to: :cast_type
# Instantiates a new column in the table.
......
module ActiveRecord
module Type
class Serialized < SimpleDelegator # :nodoc:
attr_reader :subtype
attr_reader :subtype, :coder
def initialize(subtype)
def initialize(subtype, coder)
@subtype = subtype
super
@coder = coder
super(subtype)
end
def type_cast(value)
......@@ -16,6 +17,14 @@ def type_cast(value)
end
end
def type_cast_for_write(value)
Attribute.new(coder, value, :unserialized)
end
def raw_type_cast_for_write(value)
Attribute.new(coder, value, :serialized)
end
def serialized?
true
end
......@@ -23,6 +32,26 @@ def serialized?
def accessor
ActiveRecord::Store::IndifferentHashAccessor
end
class Attribute < Struct.new(:coder, :value, :state) # :nodoc:
def unserialized_value(v = value)
state == :serialized ? unserialize(v) : value
end
def serialized_value
state == :unserialized ? serialize : value
end
def unserialize(v)
self.state = :unserialized
self.value = coder.load(v)
end
def serialize
self.state = :serialized
self.value = coder.dump(value)
end
end
end
end
end
......@@ -23,10 +23,6 @@ def type_cast(value)
cast_value(value) unless value.nil?
end
def type_cast_for_write(value)
value
end
def type_cast_for_database(value)
type_cast_for_write(value)
end
......@@ -47,10 +43,15 @@ def serialized?
false
end
def klass
def klass # :nodoc:
::Object
end
def type_cast_for_write(value) # :nodoc:
value
end
alias_method :raw_type_cast_for_write, :type_cast_for_write # :internal:
private
# Responsible for casting values from external sources to the appropriate
......
require "cases/helper"
module ActiveRecord
module AttributeMethods
class SerializationTest < ActiveSupport::TestCase
class FakeColumn < Struct.new(:name)
def type; :integer; end
def type_cast(s); "#{s}!"; end
end
class NullCoder
def load(v); v; end
end
def test_type_cast_serialized_value
value = Serialization::Attribute.new(NullCoder.new, "Hello world", :serialized)
type = Type::Serialized.new(FakeColumn.new)
assert_equal "Hello world!", type.type_cast(value)
end
def test_type_cast_unserialized_value
value = Serialization::Attribute.new(nil, "Hello world", :unserialized)
type = Type::Serialized.new(FakeColumn.new)
type.type_cast(value)
assert_equal "Hello world", type.type_cast(value)
end
end
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册