1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

update_column take ruby-land input, not database-land input

In the case of serialized columns, we would expect the unserialized
value as input, not the serialized value. The original issue which made
this distinction, #14163, introduced a bug. If you passed serialized
input to the method, it would double serialize when it was sent to the
database. You would see the wrong input upon reloading, or get an error
if you had a specific type on the serialized column.

To put it another way, `update_column` is a special case of
`update_all`, which would take `['a']` and not `['a'].to_yaml`, but you
would not pass data from `params` to it.

Fixes #18037
This commit is contained in:
Sean Griffin 2014-12-16 15:19:47 -07:00
parent e4c9bd9828
commit dd8b5fb9d3
4 changed files with 27 additions and 3 deletions

View file

@ -9,6 +9,10 @@ module ActiveRecord
FromUser.new(name, value, type)
end
def with_cast_value(name, value, type)
WithCastValue.new(name, value, type)
end
def null(name)
Null.new(name)
end
@ -58,6 +62,10 @@ module ActiveRecord
self.class.from_database(name, value, type)
end
def with_cast_value(value)
self.class.with_cast_value(name, value, type)
end
def type_cast(*)
raise NotImplementedError
end
@ -93,6 +101,16 @@ module ActiveRecord
end
end
class WithCastValue < Attribute # :nodoc:
def type_cast(value)
value
end
def changed_in_place_from?(old_value)
false
end
end
class Null < Attribute # :nodoc:
def initialize(name)
super(name, nil, Type::Value.new)

View file

@ -73,7 +73,7 @@ module ActiveRecord
if should_type_cast
@attributes.write_from_user(attr_name, value)
else
@attributes.write_from_database(attr_name, value)
@attributes.write_cast_value(attr_name, value)
end
value

View file

@ -39,6 +39,10 @@ module ActiveRecord
attributes[name] = self[name].with_value_from_user(value)
end
def write_cast_value(name, value)
attributes[name] = self[name].with_cast_value(value)
end
def freeze
@attributes.freeze
super

View file

@ -243,8 +243,9 @@ class SerializedAttributeTest < ActiveRecord::TestCase
t = Topic.create(content: "first")
assert_equal("first", t.content)
t.update_column(:content, Topic.type_for_attribute('content').type_cast_for_database("second"))
assert_equal("second", t.content)
t.update_column(:content, ["second"])
assert_equal(["second"], t.content)
assert_equal(["second"], t.reload.content)
end
def test_serialized_column_should_unserialize_after_update_attribute
@ -253,5 +254,6 @@ class SerializedAttributeTest < ActiveRecord::TestCase
t.update_attribute(:content, "second")
assert_equal("second", t.content)
assert_equal("second", t.reload.content)
end
end