Skip to content

Commit

Permalink
Restore legacy YAML compatibility for MySQL with `active_record_yaml_…
Browse files Browse the repository at this point in the history
…version: 1`

We had removed the dedicated `MysqlDateTime`, `MysqlJson`, and
`OID::Json` classes in the past (f1a0fa9, #29666), so legacy YAML
loading has no longer always perfectly compatiblity.

Fortunately, v2 (Rails 5.1 style) YAML doesn't contain type information
in almost all cases (unless serializing object using custom select), so
usually removing dedicated type affects to legacy YAML older than v1
(Rails 5.0 style) YAML only.

This restores legacy YAML compatibility for MySQL with v1 format by
adding the class alias in YAML for `MysqlString` which is most recently
reported about compatibility concern. It also affects to legacy Rails
4.2 style YAML, but 4.2 style YAML had already broken by removing
`MysqlDateTime` over 4 years ago.
  • Loading branch information
kamipo committed Jun 25, 2020
1 parent a6e98b2 commit 5b47e26
Show file tree
Hide file tree
Showing 4 changed files with 281 additions and 0 deletions.
1 change: 1 addition & 0 deletions activerecord/lib/active_record.rb
Expand Up @@ -186,3 +186,4 @@ def self.eager_load!
YAML.load_tags["!ruby/object:ActiveRecord::AttributeSet"] = "ActiveModel::AttributeSet"
YAML.load_tags["!ruby/object:ActiveRecord::Attribute::FromDatabase"] = "ActiveModel::Attribute::FromDatabase"
YAML.load_tags["!ruby/object:ActiveRecord::LazyAttributeHash"] = "ActiveModel::LazyAttributeHash"
YAML.load_tags["!ruby/object:ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::MysqlString"] = "ActiveRecord::Type::String"
18 changes: 18 additions & 0 deletions activerecord/test/cases/yaml_serialization_test.rb
Expand Up @@ -93,6 +93,24 @@ def test_a_yaml_version_is_provided_for_future_backwards_compat
assert coder["active_record_yaml_version"]
end

def test_deserializing_rails_v2_yaml
topic = YAML.load(yaml_fixture("rails_v2"))

assert_not_predicate topic, :new_record?
assert_equal 1, topic.id
assert_equal "The First Topic", topic.title
assert_equal "Have a nice day", topic.content
end

def test_deserializing_rails_v1_mysql_yaml
topic = YAML.load(yaml_fixture("rails_v1_mysql"))

assert_not_predicate topic, :new_record?
assert_equal 1, topic.id
assert_equal "The First Topic", topic.title
assert_equal "Have a nice day", topic.content
end

def test_deserializing_rails_41_yaml
topic = assert_deprecated do
YAML.load(yaml_fixture("rails_4_1"))
Expand Down
@@ -0,0 +1,207 @@
--- !ruby/object:Topic
raw_attributes:
id: 1
title: The First Topic
author_name: David
author_email_address: david@loudthinking.com
written_on: &5 2003-07-16 14:28:11.223300000 Z
bonus_time: &6 2000-01-01 14:28:00.000000000 Z
last_read: 2004-04-15
content: |
--- Have a nice day
...
important:
approved: 0
replies_count: 1
unique_replies_count: 0
parent_id:
parent_title:
type:
group:
created_at: &7 2020-06-25 10:25:48.335322000 Z
updated_at: &8 2020-06-25 10:25:48.335322000 Z
attributes: !ruby/object:ActiveRecord::AttributeSet
attributes: !ruby/object:ActiveRecord::LazyAttributeHash
types:
id: &9 !ruby/object:ActiveRecord::Type::Integer
precision:
scale:
limit:
range: !ruby/range
begin: -2147483648
end: 2147483648
excl: true
title: &10 !ruby/object:ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::MysqlString
precision:
scale:
limit: 250
author_name: &1 !ruby/object:ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::MysqlString
precision:
scale:
limit: 255
author_email_address: *1
written_on: &4 !ruby/object:ActiveRecord::Type::DateTime
precision: 6
scale:
limit:
bonus_time: &11 !ruby/object:ActiveRecord::Type::Time
precision: 0
scale:
limit:
last_read: &12 !ruby/object:ActiveRecord::Type::Date
precision:
scale:
limit:
content: &13 !ruby/object:ActiveRecord::Type::Serialized
subtype: &2 !ruby/object:ActiveRecord::Type::Text
precision:
scale:
limit: 65535
coder: !ruby/object:ActiveRecord::Coders::YAMLColumn
attr_name: :content
object_class: !ruby/class 'Object'
delegate_dc_obj: *2
important: *2
approved: &14 !ruby/object:ActiveRecord::Type::Boolean
precision:
scale:
limit:
replies_count: &3 !ruby/object:ActiveRecord::Type::Integer
precision:
scale:
limit:
range: !ruby/range
begin: -2147483648
end: 2147483648
excl: true
unique_replies_count: *3
parent_id: *3
parent_title: *1
type: *1
group: *1
created_at: *4
updated_at: *4
values:
id: 1
title: The First Topic
author_name: David
author_email_address: david@loudthinking.com
written_on: *5
bonus_time: *6
last_read: 2004-04-15
content: |
--- Have a nice day
...
important:
approved: 0
replies_count: 1
unique_replies_count: 0
parent_id:
parent_title:
type:
group:
created_at: *7
updated_at: *8
additional_types: {}
materialized: true
delegate_hash:
id: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: id
value_before_type_cast: 1
type: *9
original_attribute:
title: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: title
value_before_type_cast: The First Topic
type: *10
original_attribute:
author_name: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: author_name
value_before_type_cast: David
type: *1
original_attribute:
author_email_address: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: author_email_address
value_before_type_cast: david@loudthinking.com
type: *1
original_attribute:
written_on: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: written_on
value_before_type_cast: *5
type: *4
original_attribute:
bonus_time: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: bonus_time
value_before_type_cast: *6
type: *11
original_attribute:
last_read: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: last_read
value_before_type_cast: 2004-04-15
type: *12
original_attribute:
content: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: content
value_before_type_cast: |
--- Have a nice day
...
type: *13
original_attribute:
important: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: important
value_before_type_cast:
type: *2
original_attribute:
approved: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: approved
value_before_type_cast: 0
type: *14
original_attribute:
replies_count: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: replies_count
value_before_type_cast: 1
type: *3
original_attribute:
unique_replies_count: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: unique_replies_count
value_before_type_cast: 0
type: *3
original_attribute:
parent_id: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: parent_id
value_before_type_cast:
type: *3
original_attribute:
parent_title: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: parent_title
value_before_type_cast:
type: *1
original_attribute:
type: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: type
value_before_type_cast:
type: *1
original_attribute:
group: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: group
value_before_type_cast:
type: *1
original_attribute:
created_at: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: created_at
value_before_type_cast: *7
type: *4
original_attribute:
updated_at: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: updated_at
value_before_type_cast: *8
type: *4
original_attribute:
default_attributes:
id: !ruby/object:ActiveRecord::Attribute::FromDatabase
name: id
value_before_type_cast:
type: *9
original_attribute:
new_record: false
active_record_yaml_version: 1
55 changes: 55 additions & 0 deletions activerecord/test/support/yaml_compatibility_fixtures/rails_v2.yml
@@ -0,0 +1,55 @@
--- !ruby/object:Topic
concise_attributes:
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: id
value_before_type_cast: 1
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: title
value_before_type_cast: The First Topic
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: author_name
value_before_type_cast: David
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: author_email_address
value_before_type_cast: david@loudthinking.com
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: written_on
value_before_type_cast: '2003-07-16 14:28:11.223300'
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: bonus_time
value_before_type_cast: '2000-01-01 14:28:00'
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: last_read
value_before_type_cast: '2004-04-15'
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: content
value_before_type_cast: |
--- Have a nice day
...
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: important
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: approved
value_before_type_cast: 0
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: replies_count
value_before_type_cast: 1
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: unique_replies_count
value_before_type_cast: 0
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: parent_id
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: parent_title
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: type
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: group
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: created_at
value_before_type_cast: '2020-06-25 09:52:17.503713'
- !ruby/object:ActiveModel::Attribute::FromDatabase
name: updated_at
value_before_type_cast: '2020-06-25 09:52:17.503713'
new_record: false
active_record_yaml_version: 2

0 comments on commit 5b47e26

Please sign in to comment.