mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Attempt to provide backwards compatible YAML deserialization
I should have done this in the first place. We are now serializing an explicit version so we can make more careful changes in the future. This will load Active Record objects which were serialized in Rails 4.1. There will be bugs, as YAML serialization was at least partially broken back then. There will also be edge cases that we might not be able to handle, especially if the type of a column has changed. In addition, we're passing this as `from_database`, since that is required for serialized columns at minimum. All other types were serializing the cast value. At a glance, there should be no types for which this is a problem. Finally, dirty checking information will be lost on records serialized in 4.1, so no columns will be marked as changed.
This commit is contained in:
parent
08469012e4
commit
afc124c3b4
4 changed files with 76 additions and 0 deletions
|
@ -43,6 +43,7 @@ module ActiveRecord
|
|||
autoload :Explain
|
||||
autoload :Inheritance
|
||||
autoload :Integration
|
||||
autoload :LegacyYamlAdapter
|
||||
autoload :Migration
|
||||
autoload :Migrator, 'active_record/migration'
|
||||
autoload :ModelSchema
|
||||
|
|
|
@ -300,6 +300,7 @@ module ActiveRecord
|
|||
# post.init_with('attributes' => { 'title' => 'hello world' })
|
||||
# post.title # => 'hello world'
|
||||
def init_with(coder)
|
||||
coder = LegacyYamlAdapter.convert(self.class, coder)
|
||||
@attributes = coder['attributes']
|
||||
|
||||
init_internals
|
||||
|
@ -370,6 +371,7 @@ module ActiveRecord
|
|||
coder['raw_attributes'] = attributes_before_type_cast
|
||||
coder['attributes'] = @attributes
|
||||
coder['new_record'] = new_record?
|
||||
coder['active_record_yaml_version'] = 1
|
||||
end
|
||||
|
||||
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
|
||||
|
|
30
activerecord/lib/active_record/legacy_yaml_adapter.rb
Normal file
30
activerecord/lib/active_record/legacy_yaml_adapter.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
module ActiveRecord
|
||||
module LegacyYamlAdapter
|
||||
def self.convert(klass, coder)
|
||||
return coder unless coder.is_a?(Psych::Coder)
|
||||
|
||||
case coder["active_record_yaml_version"]
|
||||
when 1 then coder
|
||||
else
|
||||
if coder["attributes"].is_a?(AttributeSet)
|
||||
coder
|
||||
else
|
||||
Rails41.convert(klass, coder)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Rails41
|
||||
def self.convert(klass, coder)
|
||||
attributes = klass.attributes_builder
|
||||
.build_from_database(coder["attributes"])
|
||||
new_record = coder["attributes"][klass.primary_key].blank?
|
||||
|
||||
{
|
||||
"attributes" => attributes,
|
||||
"new_record" => new_record,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -83,4 +83,47 @@ class YamlSerializationTest < ActiveRecord::TestCase
|
|||
assert_equal 5, author.posts_count
|
||||
assert_equal 5, dumped.posts_count
|
||||
end
|
||||
|
||||
def test_a_yaml_version_is_provided_for_future_backwards_compat
|
||||
coder = {}
|
||||
Topic.first.encode_with(coder)
|
||||
|
||||
assert coder['active_record_yaml_version']
|
||||
end
|
||||
|
||||
def test_deserializing_rails_41_yaml
|
||||
yaml = <<-YAML.strip_heredoc
|
||||
--- !ruby/object:Topic
|
||||
attributes:
|
||||
id:
|
||||
title: The First Topic
|
||||
author_name: David
|
||||
author_email_address: david@loudthinking.com
|
||||
written_on: 2003-07-16 14:28:11.223300000 Z
|
||||
bonus_time: 2000-01-01 14:28:00.000000000 Z
|
||||
last_read: 2004-04-15
|
||||
content: |
|
||||
---
|
||||
:omg: :lol
|
||||
important:
|
||||
approved: false
|
||||
replies_count: 1
|
||||
unique_replies_count: 0
|
||||
parent_id:
|
||||
parent_title:
|
||||
type:
|
||||
group:
|
||||
created_at: 2015-03-10 17:05:42.000000000 Z
|
||||
updated_at: 2015-03-10 17:05:42.000000000 Z
|
||||
YAML
|
||||
topic = YAML.load(yaml)
|
||||
|
||||
assert topic.new_record?
|
||||
assert_equal nil, topic.id
|
||||
assert_equal "The First Topic", topic.title
|
||||
assert_equal({ omg: :lol }, topic.content)
|
||||
end
|
||||
|
||||
def test_deserializing_rails_42_yaml
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue