aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/attribute.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/attribute.rb')
-rw-r--r--activerecord/lib/active_record/attribute.rb166
1 files changed, 98 insertions, 68 deletions
diff --git a/activerecord/lib/active_record/attribute.rb b/activerecord/lib/active_record/attribute.rb
index 3c4c8f10ec..0b08c2a39b 100644
--- a/activerecord/lib/active_record/attribute.rb
+++ b/activerecord/lib/active_record/attribute.rb
@@ -65,7 +65,7 @@ module ActiveRecord
def with_value_from_user(value)
type.assert_valid_value(value)
- self.class.from_user(name, value, type, self)
+ self.class.from_user(name, value, type, original_attribute || self)
end
def with_value_from_database(value)
@@ -77,7 +77,11 @@ module ActiveRecord
end
def with_type(type)
- self.class.new(name, value_before_type_cast, type, original_attribute)
+ if changed_in_place?
+ with_value_from_user(value).with_type(type)
+ else
+ self.class.new(name, value_before_type_cast, type, original_attribute)
+ end
end
def type_cast(*)
@@ -108,100 +112,126 @@ module ActiveRecord
[self.class, name, value_before_type_cast, type].hash
end
- protected
-
- attr_reader :original_attribute
- alias_method :assigned?, :original_attribute
-
- def initialize_dup(other)
- if defined?(@value) && @value.duplicable?
- @value = @value.dup
- end
+ def init_with(coder)
+ @name = coder["name"]
+ @value_before_type_cast = coder["value_before_type_cast"]
+ @type = coder["type"]
+ @original_attribute = coder["original_attribute"]
+ @value = coder["value"] if coder.map.key?("value")
end
- def changed_from_assignment?
- assigned? && type.changed?(original_value, value, value_before_type_cast)
+ def encode_with(coder)
+ coder["name"] = name
+ coder["value_before_type_cast"] = value_before_type_cast if value_before_type_cast
+ coder["type"] = type if type
+ coder["original_attribute"] = original_attribute if original_attribute
+ coder["value"] = value if defined?(@value)
end
- def original_value_for_database
- if assigned?
- original_attribute.original_value_for_database
- else
- _original_value_for_database
- end
- end
+ protected
- def _original_value_for_database
- value_for_database
- end
+ attr_reader :original_attribute
+ alias_method :assigned?, :original_attribute
- class FromDatabase < Attribute # :nodoc:
- def type_cast(value)
- type.deserialize(value)
+ def initialize_dup(other)
+ if defined?(@value) && @value.duplicable?
+ @value = @value.dup
+ end
end
- def _original_value_for_database
- value_before_type_cast
+ def changed_from_assignment?
+ assigned? && type.changed?(original_value, value, value_before_type_cast)
end
- end
- class FromUser < Attribute # :nodoc:
- def type_cast(value)
- type.cast(value)
+ def original_value_for_database
+ if assigned?
+ original_attribute.original_value_for_database
+ else
+ _original_value_for_database
+ end
end
- def came_from_user?
- true
+ def _original_value_for_database
+ type.serialize(original_value)
end
- end
- class WithCastValue < Attribute # :nodoc:
- def type_cast(value)
- value
- end
+ class FromDatabase < Attribute # :nodoc:
+ def type_cast(value)
+ type.deserialize(value)
+ end
- def changed_in_place_from?(old_value)
- false
+ def _original_value_for_database
+ value_before_type_cast
+ end
end
- end
- class Null < Attribute # :nodoc:
- def initialize(name)
- super(name, nil, Type::Value.new)
- end
+ class FromUser < Attribute # :nodoc:
+ def type_cast(value)
+ type.cast(value)
+ end
- def value
- nil
+ def came_from_user?
+ true
+ end
end
- def with_type(type)
- self.class.with_cast_value(name, nil, type)
- end
+ class WithCastValue < Attribute # :nodoc:
+ def type_cast(value)
+ value
+ end
- def with_value_from_database(value)
- raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{name}`"
+ def changed_in_place?
+ false
+ end
end
- alias_method :with_value_from_user, :with_value_from_database
- end
- class Uninitialized < Attribute # :nodoc:
- def initialize(name, type)
- super(name, nil, type)
- end
+ class Null < Attribute # :nodoc:
+ def initialize(name)
+ super(name, nil, Type.default_value)
+ end
- def value
- if block_given?
- yield name
+ def type_cast(*)
+ nil
+ end
+
+ def with_type(type)
+ self.class.with_cast_value(name, nil, type)
end
- end
- def value_for_database
+ def with_value_from_database(value)
+ raise ActiveModel::MissingAttributeError, "can't write unknown attribute `#{name}`"
+ end
+ alias_method :with_value_from_user, :with_value_from_database
end
- def initialized?
- false
+ class Uninitialized < Attribute # :nodoc:
+ UNINITIALIZED_ORIGINAL_VALUE = Object.new
+
+ def initialize(name, type)
+ super(name, nil, type)
+ end
+
+ def value
+ if block_given?
+ yield name
+ end
+ end
+
+ def original_value
+ UNINITIALIZED_ORIGINAL_VALUE
+ end
+
+ def value_for_database
+ end
+
+ def initialized?
+ false
+ end
+
+ def with_type(type)
+ self.class.new(name, type)
+ end
end
- end
- private_constant :FromDatabase, :FromUser, :Null, :Uninitialized, :WithCastValue
+ private_constant :FromDatabase, :FromUser, :Null, :Uninitialized, :WithCastValue
end
end