701 lines
20 KiB
Ruby
701 lines
20 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "cases/helper"
|
|
require "models/person"
|
|
require "models/traffic_light"
|
|
require "models/post"
|
|
|
|
class SerializedAttributeTest < ActiveRecord::TestCase
|
|
def setup
|
|
ActiveRecord.use_yaml_unsafe_load = true
|
|
@yaml_column_permitted_classes_default = ActiveRecord.yaml_column_permitted_classes
|
|
end
|
|
|
|
def teardown
|
|
Topic.serialize("content")
|
|
ActiveRecord.yaml_column_permitted_classes = @yaml_column_permitted_classes_default
|
|
end
|
|
|
|
fixtures :topics, :posts
|
|
|
|
MyObject = Struct.new :attribute1, :attribute2
|
|
|
|
class Topic < ActiveRecord::Base
|
|
serialize :content
|
|
end
|
|
|
|
class ImportantTopic < Topic
|
|
serialize :important, type: Hash
|
|
end
|
|
|
|
class ClassifiedTopic < Topic
|
|
serialize :important, type: Class
|
|
end
|
|
|
|
def test_serialize_does_not_eagerly_load_columns
|
|
Topic.reset_column_information
|
|
assert_no_queries do
|
|
Topic.serialize(:content)
|
|
end
|
|
end
|
|
|
|
def test_serialized_attribute
|
|
Topic.serialize("content", type: MyObject)
|
|
|
|
myobj = MyObject.new("value1", "value2")
|
|
topic = Topic.create("content" => myobj)
|
|
assert_equal(myobj, topic.content)
|
|
|
|
topic.reload
|
|
assert_equal(myobj, topic.content)
|
|
end
|
|
|
|
def test_serialized_attribute_on_alias_attribute
|
|
klass = Class.new(ActiveRecord::Base) do
|
|
self.table_name = Topic.table_name
|
|
alias_attribute :object, :content
|
|
serialize :object, type: MyObject
|
|
end
|
|
|
|
myobj = MyObject.new("value1", "value2")
|
|
topic = klass.create!(object: myobj)
|
|
assert_equal(myobj, topic.object)
|
|
|
|
topic.reload
|
|
assert_equal(myobj, topic.object)
|
|
end
|
|
|
|
def test_serialized_attribute_with_default
|
|
klass = Class.new(ActiveRecord::Base) do
|
|
self.table_name = Topic.table_name
|
|
serialize(:content, type: Hash, default: { key: "value" })
|
|
end
|
|
|
|
t = klass.new
|
|
assert_equal({ key: "value" }, t.content)
|
|
end
|
|
|
|
def test_serialized_attribute_on_custom_attribute_with_default
|
|
klass = Class.new(ActiveRecord::Base) do
|
|
self.table_name = Topic.table_name
|
|
attribute :content, default: { key: "value" }
|
|
serialize :content, type: Hash
|
|
end
|
|
|
|
t = klass.new
|
|
assert_equal({ key: "value" }, t.content)
|
|
end
|
|
|
|
def test_serialized_attribute_in_base_class
|
|
Topic.serialize("content", type: Hash)
|
|
|
|
hash = { "content1" => "value1", "content2" => "value2" }
|
|
important_topic = ImportantTopic.create("content" => hash)
|
|
assert_equal(hash, important_topic.content)
|
|
|
|
important_topic.reload
|
|
assert_equal(hash, important_topic.content)
|
|
end
|
|
|
|
def test_serialized_attributes_from_database_on_subclass
|
|
Topic.serialize :content, type: Hash
|
|
|
|
t = ImportantTopic.new(content: { foo: :bar })
|
|
assert_equal({ foo: :bar }, t.content)
|
|
t.save!
|
|
t = ImportantTopic.last
|
|
assert_equal({ foo: :bar }, t.content)
|
|
end
|
|
|
|
def test_serialized_attribute_calling_dup_method
|
|
Topic.serialize :content, coder: JSON
|
|
|
|
orig = Topic.new(content: { foo: :bar })
|
|
clone = orig.dup
|
|
assert_equal(orig.content, clone.content)
|
|
end
|
|
|
|
def test_serialized_json_attribute_returns_unserialized_value
|
|
Topic.serialize :content, coder: JSON
|
|
my_post = posts(:welcome)
|
|
|
|
t = Topic.new(content: my_post)
|
|
t.save!
|
|
t.reload
|
|
|
|
assert_instance_of(Hash, t.content)
|
|
assert_equal(my_post.id, t.content["id"])
|
|
assert_equal(my_post.title, t.content["title"])
|
|
end
|
|
|
|
def test_json_read_legacy_null
|
|
Topic.serialize :content, coder: JSON
|
|
|
|
# Force a row to have a JSON "null" instead of a database NULL (this is how
|
|
# null values are saved on 4.1 and before)
|
|
id = Topic.lease_connection.insert "INSERT INTO topics (content) VALUES('null')"
|
|
t = Topic.find(id)
|
|
|
|
assert_nil t.content
|
|
end
|
|
|
|
def test_json_read_db_null
|
|
Topic.serialize :content, coder: JSON
|
|
|
|
# Force a row to have a database NULL instead of a JSON "null"
|
|
id = Topic.lease_connection.insert "INSERT INTO topics (content) VALUES(NULL)"
|
|
t = Topic.find(id)
|
|
|
|
assert_nil t.content
|
|
end
|
|
|
|
def test_serialized_attribute_declared_in_subclass
|
|
hash = { "important1" => "value1", "important2" => "value2" }
|
|
important_topic = ImportantTopic.create("important" => hash)
|
|
assert_equal(hash, important_topic.important)
|
|
|
|
important_topic.reload
|
|
assert_equal(hash, important_topic.important)
|
|
assert_equal(hash, important_topic.read_attribute(:important))
|
|
end
|
|
|
|
def test_serialized_time_attribute
|
|
myobj = Time.local(2008, 1, 1, 1, 0)
|
|
topic = Topic.create("content" => myobj).reload
|
|
assert_equal(myobj, topic.content)
|
|
end
|
|
|
|
def test_serialized_string_attribute
|
|
myobj = "Yes"
|
|
topic = Topic.create("content" => myobj).reload
|
|
assert_equal(myobj, topic.content)
|
|
end
|
|
|
|
def test_serialized_class_attribute
|
|
ActiveRecord.yaml_column_permitted_classes += [Class]
|
|
|
|
topic = ClassifiedTopic.create(important: Symbol).reload
|
|
assert_equal(Symbol, topic.important)
|
|
assert_not_empty ClassifiedTopic.where(important: Symbol)
|
|
end
|
|
|
|
def test_serialized_class_does_not_become_frozen
|
|
ActiveRecord.yaml_column_permitted_classes += [Class]
|
|
|
|
assert_not_predicate Symbol, :frozen?
|
|
ClassifiedTopic.create(important: Symbol)
|
|
assert_not_empty ClassifiedTopic.where(important: Symbol)
|
|
assert_not_predicate Symbol, :frozen?
|
|
end
|
|
|
|
def test_nil_serialized_attribute_without_class_constraint
|
|
topic = Topic.new
|
|
assert_nil topic.content
|
|
end
|
|
|
|
def test_nil_not_serialized_without_class_constraint
|
|
assert Topic.new(content: nil).save
|
|
assert_equal 1, Topic.where(content: nil).count
|
|
end
|
|
|
|
def test_nil_not_serialized_with_class_constraint
|
|
Topic.serialize :content, type: Hash
|
|
assert Topic.new(content: nil).save
|
|
assert_equal 1, Topic.where(content: nil).count
|
|
end
|
|
|
|
def test_serialized_attribute_should_raise_exception_on_assignment_with_wrong_type
|
|
Topic.serialize(:content, type: Hash)
|
|
assert_raise(ActiveRecord::SerializationTypeMismatch) do
|
|
Topic.new(content: "string")
|
|
end
|
|
end
|
|
|
|
def test_should_raise_exception_on_serialized_attribute_with_type_mismatch
|
|
myobj = MyObject.new("value1", "value2")
|
|
topic = Topic.new(content: myobj)
|
|
assert topic.save
|
|
Topic.serialize(:content, type: Hash)
|
|
assert_raise(ActiveRecord::SerializationTypeMismatch) { Topic.find(topic.id).content }
|
|
end
|
|
|
|
def test_serialized_attribute_with_class_constraint
|
|
settings = { "color" => "blue" }
|
|
Topic.serialize(:content, type: Hash)
|
|
topic = Topic.new(content: settings)
|
|
assert topic.save
|
|
assert_equal(settings, Topic.find(topic.id).content)
|
|
end
|
|
|
|
def test_where_by_serialized_attribute_with_array
|
|
settings = [ "color" => "green" ]
|
|
Topic.serialize(:content, type: Array)
|
|
topic = Topic.create!(content: settings)
|
|
assert_equal topic, Topic.where(content: settings).take
|
|
end
|
|
|
|
def test_where_by_serialized_attribute_with_hash
|
|
settings = { "color" => "green" }
|
|
Topic.serialize(:content, type: Hash)
|
|
topic = Topic.create!(content: settings)
|
|
assert_equal topic, Topic.where(content: settings).take
|
|
end
|
|
|
|
def test_where_by_serialized_attribute_with_hash_in_array
|
|
settings = { "color" => "green" }
|
|
Topic.serialize(:content, type: Hash)
|
|
topic = Topic.create!(content: settings)
|
|
assert_equal topic, Topic.where(content: [settings, { "herring" => "red" }]).take
|
|
end
|
|
|
|
def test_serialized_default_class
|
|
Topic.serialize(:content, type: Hash)
|
|
topic = Topic.new
|
|
assert_equal Hash, topic.content.class
|
|
assert_equal Hash, topic.read_attribute(:content).class
|
|
topic.content["beer"] = "MadridRb"
|
|
assert topic.save
|
|
topic.reload
|
|
assert_equal Hash, topic.content.class
|
|
assert_equal "MadridRb", topic.content["beer"]
|
|
end
|
|
|
|
def test_serialized_no_default_class_for_object
|
|
topic = Topic.new
|
|
assert_nil topic.content
|
|
end
|
|
|
|
def test_serialized_boolean_value_true
|
|
topic = Topic.new(content: true)
|
|
assert topic.save
|
|
topic = topic.reload
|
|
assert_equal true, topic.content
|
|
end
|
|
|
|
def test_serialized_boolean_value_false
|
|
topic = Topic.new(content: false)
|
|
assert topic.save
|
|
topic = topic.reload
|
|
assert_equal false, topic.content
|
|
end
|
|
|
|
def test_serialize_with_coder
|
|
some_class = Struct.new(:foo) do
|
|
def self.dump(value)
|
|
value.foo
|
|
end
|
|
|
|
def self.load(value)
|
|
new(value)
|
|
end
|
|
end
|
|
|
|
Topic.serialize(:content, coder: some_class)
|
|
topic = Topic.new(content: some_class.new("my value"))
|
|
topic.save!
|
|
topic.reload
|
|
assert_kind_of some_class, topic.content
|
|
assert_equal some_class.new("my value"), topic.content
|
|
end
|
|
|
|
def test_serialize_attribute_via_select_method_when_time_zone_available
|
|
with_timezone_config aware_attributes: true do
|
|
Topic.serialize(:content, type: MyObject)
|
|
|
|
myobj = MyObject.new("value1", "value2")
|
|
topic = Topic.create(content: myobj)
|
|
|
|
assert_equal(myobj, Topic.select(:content).find(topic.id).content)
|
|
assert_raise(ActiveModel::MissingAttributeError) { Topic.select(:id).find(topic.id).content }
|
|
end
|
|
end
|
|
|
|
def test_serialize_attribute_can_be_serialized_in_an_integer_column
|
|
insures = ["life"]
|
|
person = SerializedPerson.new(first_name: "David", insures: insures)
|
|
assert person.save
|
|
person = person.reload
|
|
assert_equal(insures, person.insures)
|
|
end
|
|
|
|
def test_regression_serialized_default_on_text_column_with_null_false
|
|
light = TrafficLight.new
|
|
assert_equal [], light.state
|
|
assert_equal [], light.long_state
|
|
end
|
|
|
|
def test_unexpected_serialized_type
|
|
Topic.serialize :content, type: Hash
|
|
topic = Topic.create!(content: { zomg: true })
|
|
|
|
Topic.serialize :content, type: Array
|
|
|
|
topic.reload
|
|
error = assert_raise(ActiveRecord::SerializationTypeMismatch) do
|
|
topic.content
|
|
end
|
|
expected = "can't load `content`: was supposed to be a Array, but was a Hash. -- {:zomg=>true}"
|
|
assert_equal expected, error.to_s
|
|
end
|
|
|
|
def test_serialized_column_should_unserialize_after_update_column
|
|
t = Topic.create(content: "first")
|
|
assert_equal("first", 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
|
|
t = Topic.create(content: "first")
|
|
assert_equal("first", t.content)
|
|
|
|
t.update_attribute(:content, "second")
|
|
assert_equal("second", t.content)
|
|
assert_equal("second", t.reload.content)
|
|
end
|
|
|
|
def test_nil_is_not_changed_when_serialized_with_a_class
|
|
Topic.serialize(:content, type: Array)
|
|
|
|
topic = Topic.new(content: nil)
|
|
|
|
assert_not_predicate topic, :content_changed?
|
|
end
|
|
|
|
def test_classes_without_no_arg_constructors_are_not_supported
|
|
assert_raises(ArgumentError) do
|
|
Topic.serialize(:content, type: Regexp)
|
|
end
|
|
end
|
|
|
|
def test_newly_emptied_serialized_hash_is_changed
|
|
Topic.serialize(:content, type: Hash)
|
|
topic = Topic.create(content: { "things" => "stuff" })
|
|
topic.content.delete("things")
|
|
topic.save!
|
|
topic.reload
|
|
|
|
assert_equal({}, topic.content)
|
|
end
|
|
|
|
def test_is_not_changed_when_stored_blob
|
|
Topic.serialize(:binary_content, type: Array)
|
|
Topic.serialize(:content, type: Array)
|
|
|
|
value = %w(Fée)
|
|
model = Topic.create!(binary_content: value, content: value)
|
|
model.reload
|
|
|
|
model.binary_content = value
|
|
assert_not_predicate model, :binary_content_changed?
|
|
|
|
model.content = value
|
|
assert_not_predicate model, :content_changed?
|
|
end
|
|
|
|
class FrozenCoder < ActiveRecord::Coders::YAMLColumn
|
|
def dump(obj)
|
|
super&.freeze
|
|
end
|
|
end
|
|
|
|
def test_is_not_changed_when_stored_in_blob_frozen_payload
|
|
Topic.serialize(:binary_content, coder: FrozenCoder.new(:binary_content, Array))
|
|
Topic.serialize(:content, coder: FrozenCoder.new(:content, Array))
|
|
|
|
value = %w(Fée)
|
|
model = Topic.create!(binary_content: value, content: value)
|
|
model.reload
|
|
|
|
model.content = value
|
|
assert_not_predicate model, :content_changed?
|
|
end
|
|
|
|
def test_values_cast_from_nil_are_persisted_as_nil
|
|
# This is required to fulfil the following contract, which must be universally
|
|
# true in Active Record:
|
|
#
|
|
# model.attribute = value
|
|
# assert_equal model.attribute, model.tap(&:save).reload.attribute
|
|
Topic.serialize(:content, type: Hash)
|
|
topic = Topic.create!(content: {})
|
|
topic2 = Topic.create!(content: nil)
|
|
|
|
assert_equal [topic, topic2], Topic.where(content: nil).sort_by(&:id)
|
|
end
|
|
|
|
def test_serialized_attribute_can_be_defined_in_abstract_classes
|
|
klass = Class.new(ActiveRecord::Base) do
|
|
self.abstract_class = true
|
|
self.table_name = nil
|
|
serialize(:content, type: Hash)
|
|
end
|
|
|
|
subclass = Class.new(klass) do
|
|
self.table_name = "topics"
|
|
end
|
|
|
|
subclass.define_attribute_methods
|
|
|
|
topic = subclass.create!(content: { foo: 1 })
|
|
assert_equal [topic], subclass.where(content: { foo: 1 }).to_a
|
|
end
|
|
|
|
def test_nil_is_always_persisted_as_null
|
|
Topic.serialize(:content, type: Hash)
|
|
|
|
topic = Topic.create!(content: { foo: "bar" })
|
|
topic.update_attribute :content, nil
|
|
assert_equal [topic], Topic.where(content: nil)
|
|
end
|
|
|
|
class EncryptedType < ActiveRecord::Type::Text
|
|
include ActiveModel::Type::Helpers::Mutable
|
|
|
|
attr_reader :subtype, :encryptor
|
|
|
|
def initialize(subtype: ActiveModel::Type::String.new)
|
|
super()
|
|
|
|
@subtype = subtype
|
|
@encryptor = ActiveSupport::MessageEncryptor.new("abcd" * 8)
|
|
end
|
|
|
|
def serialize(value)
|
|
subtype.serialize(value).yield_self do |cleartext|
|
|
encryptor.encrypt_and_sign(cleartext) unless cleartext.nil?
|
|
end
|
|
end
|
|
|
|
def deserialize(ciphertext)
|
|
encryptor.decrypt_and_verify(ciphertext)
|
|
.yield_self { |cleartext| subtype.deserialize(cleartext) } unless ciphertext.nil?
|
|
end
|
|
|
|
def changed_in_place?(old, new)
|
|
if old.nil?
|
|
!new.nil?
|
|
else
|
|
deserialize(old) != new
|
|
end
|
|
end
|
|
end
|
|
|
|
def test_decorated_type_with_type_for_attribute
|
|
old_registry = ActiveRecord::Type.registry
|
|
ActiveRecord::Type.registry = ActiveRecord::Type.registry.dup
|
|
ActiveRecord::Type.register :encrypted, EncryptedType
|
|
|
|
klass = Class.new(ActiveRecord::Base) do
|
|
self.table_name = Topic.table_name
|
|
store :content, coder: ActiveRecord::Coders::JSON
|
|
attribute :content, :encrypted, subtype: type_for_attribute(:content)
|
|
end
|
|
|
|
topic = klass.create!(content: { trial: true })
|
|
|
|
assert_equal({ "trial" => true }, topic.content)
|
|
ensure
|
|
ActiveRecord::Type.registry = old_registry
|
|
end
|
|
|
|
def test_decorated_type_with_decorator_block
|
|
klass = Class.new(ActiveRecord::Base) do
|
|
self.table_name = Topic.table_name
|
|
store :content, coder: ActiveRecord::Coders::JSON
|
|
decorate_attributes([:content]) do |name, type|
|
|
EncryptedType.new(subtype: type)
|
|
end
|
|
end
|
|
|
|
topic = klass.create!(content: { trial: true })
|
|
assert_equal({ "trial" => true }, topic.content)
|
|
end
|
|
|
|
def test_mutation_detection_does_not_double_serialize
|
|
coder = Object.new
|
|
def coder.dump(value)
|
|
return if value.nil?
|
|
value + " encoded"
|
|
end
|
|
def coder.load(value)
|
|
return if value.nil?
|
|
value.gsub(" encoded", "")
|
|
end
|
|
type = Class.new(ActiveModel::Type::Value) do
|
|
include ActiveModel::Type::Helpers::Mutable
|
|
|
|
def serialize(value)
|
|
return if value.nil?
|
|
value + " serialized"
|
|
end
|
|
|
|
def deserialize(value)
|
|
return if value.nil?
|
|
value.gsub(" serialized", "")
|
|
end
|
|
end.new
|
|
model = Class.new(Topic) do
|
|
attribute :foo, type
|
|
serialize :foo, coder: coder
|
|
end
|
|
|
|
topic = model.create!(foo: "bar")
|
|
topic.foo
|
|
assert_not_predicate topic, :changed?
|
|
end
|
|
|
|
def test_serialized_attribute_works_under_concurrent_initial_access
|
|
model = Class.new(Topic)
|
|
|
|
topic = model.create!
|
|
topic.update group: "1"
|
|
|
|
model.serialize :group, coder: JSON
|
|
model.reset_column_information
|
|
|
|
# This isn't strictly necessary for the test, but a little bit of
|
|
# knowledge of internals allows us to make failures far more likely.
|
|
model.define_singleton_method(:define_attribute) do |*args, **options|
|
|
Thread.pass
|
|
super(*args, **options)
|
|
end
|
|
|
|
threads = 4.times.map do
|
|
Thread.new do
|
|
topic.reload.group
|
|
end
|
|
end
|
|
|
|
# All the threads should retrieve the value knowing it is JSON, and
|
|
# thus decode it. If this fails, some threads will instead see the
|
|
# raw string ("1"), or raise an exception.
|
|
assert_equal [1] * threads.size, threads.map(&:value)
|
|
end
|
|
end
|
|
|
|
class SerializedAttributeTestWithYamlSafeLoad < SerializedAttributeTest
|
|
def setup
|
|
@use_yaml_unsafe_load = ActiveRecord.use_yaml_unsafe_load
|
|
@yaml_column_permitted_classes_default = ActiveRecord.yaml_column_permitted_classes
|
|
ActiveRecord.use_yaml_unsafe_load = false
|
|
end
|
|
|
|
def teardown
|
|
Topic.serialize("content")
|
|
ActiveRecord.yaml_column_permitted_classes = @yaml_column_permitted_classes_default
|
|
ActiveRecord.use_yaml_unsafe_load = @use_yaml_unsafe_load
|
|
end
|
|
|
|
def test_serialized_attribute
|
|
Topic.serialize("content", type: String)
|
|
|
|
myobj = String.new("value1")
|
|
topic = Topic.create("content" => myobj)
|
|
assert_equal(myobj, topic.content)
|
|
|
|
topic.reload
|
|
assert_equal(myobj, topic.content)
|
|
end
|
|
|
|
def test_serialized_attribute_on_custom_attribute_with_default
|
|
klass = Class.new(ActiveRecord::Base) do
|
|
self.table_name = Topic.table_name
|
|
attribute :content, default: { "key" => "value" }
|
|
serialize :content, type: Hash
|
|
end
|
|
|
|
t = klass.new
|
|
assert_equal({ "key" => "value" }, t.content)
|
|
end
|
|
|
|
def test_nil_is_always_persisted_as_null
|
|
Topic.serialize(:content, type: Hash)
|
|
|
|
topic = Topic.create!(content: { "foo" => "bar" })
|
|
topic.update_attribute :content, nil
|
|
assert_equal [topic], Topic.where(content: nil)
|
|
end
|
|
|
|
def test_serialized_attribute_with_default
|
|
klass = Class.new(ActiveRecord::Base) do
|
|
self.table_name = Topic.table_name
|
|
serialize(:content, type: Hash, default: { "key" => "value" })
|
|
end
|
|
|
|
t = klass.new
|
|
assert_equal({ "key" => "value" }, t.content)
|
|
end
|
|
|
|
def test_serialized_attributes_from_database_on_subclass
|
|
Topic.serialize :content, type: Hash
|
|
|
|
t = ImportantTopic.new(content: { "foo" => "bar" })
|
|
assert_equal({ "foo" => "bar" }, t.content)
|
|
t.save!
|
|
t = ImportantTopic.last
|
|
assert_equal({ "foo" => "bar" }, t.content)
|
|
end
|
|
|
|
def test_serialized_attribute_on_alias_attribute
|
|
klass = Class.new(ActiveRecord::Base) do
|
|
self.table_name = Topic.table_name
|
|
alias_attribute :object, :content
|
|
serialize :object, type: Hash
|
|
end
|
|
|
|
myobj = { "somevalue" => "thevalue" }
|
|
topic = klass.create!(object: myobj)
|
|
assert_equal(myobj, topic.object)
|
|
|
|
topic.reload
|
|
assert_equal(myobj, topic.object)
|
|
end
|
|
|
|
def test_unexpected_serialized_type
|
|
Topic.serialize :content, type: Hash
|
|
topic = Topic.create!(content: { "zomg" => true })
|
|
|
|
Topic.serialize :content, type: Array
|
|
|
|
topic.reload
|
|
error = assert_raise(ActiveRecord::SerializationTypeMismatch) do
|
|
topic.content
|
|
end
|
|
expected = "can't load `content`: was supposed to be a Array, but was a Hash. -- {\"zomg\"=>true}"
|
|
assert_equal expected, error.to_s
|
|
end
|
|
|
|
def test_serialize_attribute_via_select_method_when_time_zone_available
|
|
with_timezone_config aware_attributes: true do
|
|
Topic.serialize(:content, type: Hash)
|
|
|
|
myobj = { "somevalue" => "thevalue" }
|
|
topic = Topic.create(content: myobj)
|
|
|
|
assert_equal(myobj, Topic.select(:content).find(topic.id).content)
|
|
assert_raise(ActiveModel::MissingAttributeError) { Topic.select(:id).find(topic.id).content }
|
|
end
|
|
end
|
|
|
|
def test_should_raise_exception_on_serialized_attribute_with_type_mismatch
|
|
myobj = { "somevalue" => "thevalue" }
|
|
topic = Topic.new(content: myobj)
|
|
assert topic.save
|
|
Topic.serialize(:content, type: String)
|
|
assert_raise(ActiveRecord::SerializationTypeMismatch) { Topic.find(topic.id).content }
|
|
end
|
|
|
|
def test_serialized_time_attribute
|
|
skip "Time is a DisallowedClass in Psych safe_load()."
|
|
end
|
|
|
|
def test_supports_permitted_classes_for_default_column_serializer
|
|
Topic.serialize(:content, yaml: { permitted_classes: [Time] })
|
|
topic = Topic.new(content: Time.now)
|
|
assert topic.save
|
|
end
|
|
end
|