mirror of https://github.com/rails/rails
Merge pull request #46231 from jonathanhefner/active_model-memoize-value_for_database
Avoid unnecessary `serialize` calls after save
This commit is contained in:
commit
caf9413604
|
@ -53,7 +53,10 @@ module ActiveModel
|
|||
end
|
||||
|
||||
def value_for_database
|
||||
type.serialize(value)
|
||||
if !defined?(@value_for_database) || type.changed_in_place?(@value_for_database, value)
|
||||
@value_for_database = _value_for_database
|
||||
end
|
||||
@value_for_database
|
||||
end
|
||||
|
||||
def serializable?(&block)
|
||||
|
@ -159,6 +162,10 @@ module ActiveModel
|
|||
assigned? && type.changed?(original_value, value, value_before_type_cast)
|
||||
end
|
||||
|
||||
def _value_for_database
|
||||
type.serialize(value)
|
||||
end
|
||||
|
||||
def _original_value_for_database
|
||||
type.serialize(original_value)
|
||||
end
|
||||
|
@ -179,13 +186,14 @@ module ActiveModel
|
|||
type.cast(value)
|
||||
end
|
||||
|
||||
def value_for_database
|
||||
Type::SerializeCastValue.serialize(type, value)
|
||||
end
|
||||
|
||||
def came_from_user?
|
||||
!type.value_constructed_by_mass_assignment?(value_before_type_cast)
|
||||
end
|
||||
|
||||
private
|
||||
def _value_for_database
|
||||
Type::SerializeCastValue.serialize(type, value)
|
||||
end
|
||||
end
|
||||
|
||||
class WithCastValue < Attribute # :nodoc:
|
||||
|
|
|
@ -5,6 +5,10 @@ require "cases/helper"
|
|||
module ActiveModel
|
||||
class AttributeTest < ActiveModel::TestCase
|
||||
class InscribingType
|
||||
def changed_in_place?(raw_old_value, new_value)
|
||||
false
|
||||
end
|
||||
|
||||
def cast(value)
|
||||
"cast(#{value})"
|
||||
end
|
||||
|
@ -96,6 +100,37 @@ module ActiveModel
|
|||
assert_equal "serialize_cast_value(cast(whatever))", attribute.value_for_database
|
||||
end
|
||||
|
||||
test "value_for_database is memoized" do
|
||||
count = 0
|
||||
@type.define_singleton_method(:serialize) do |value|
|
||||
count += 1
|
||||
nil
|
||||
end
|
||||
|
||||
attribute = Attribute.from_user(nil, "whatever", @type)
|
||||
|
||||
attribute.value_for_database
|
||||
attribute.value_for_database
|
||||
assert_equal 1, count
|
||||
end
|
||||
|
||||
test "value_for_database is recomputed when value changes in place" do
|
||||
count = 0
|
||||
@type.define_singleton_method(:serialize) do |value|
|
||||
count += 1
|
||||
nil
|
||||
end
|
||||
@type.define_singleton_method(:changed_in_place?) do |*|
|
||||
true
|
||||
end
|
||||
|
||||
attribute = Attribute.from_user(nil, "whatever", @type)
|
||||
|
||||
attribute.value_for_database
|
||||
attribute.value_for_database
|
||||
assert_equal 2, count
|
||||
end
|
||||
|
||||
test "duping dups the value" do
|
||||
attribute = Attribute.from_database(nil, "a value", @type)
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def value_for_database
|
||||
@value_for_database ||= super
|
||||
@value_for_database = _value_for_database unless defined?(@value_for_database)
|
||||
@value_for_database
|
||||
end
|
||||
|
||||
def with_cast_value(value)
|
||||
|
|
Loading…
Reference in New Issue