Trying to deserialize a very simple object using YAML.load
or Marshal.load
produces a corrupted object because the class which belongs to is not required on the deserializing process.
Example:
# app/models/my_model.rb
class MyModel
attr_accessor :id
end
# test/unit/serializing_test.rb
require 'test_helper'
class SerializingTest < Test::Unit::TestCase
def test_yaml_serialize_structure
my_model = MyModel.new
my_model.id = 'my model'
File.open( "#{Rails.root}/tmp/object.yml" , 'w' ) do |f|
YAML::dump(my_model, f)
end
end
def test_yaml_deserialize_structure
object = YAML.load_file "#{Rails.root}/tmp/object.yml"
assert( object.instance_of? MyModel )
assert_equal( 'my model', object.id )
end
end
With this code we can run this shell console session without any error:
$ ruby -Itest test/unit/serializing_test.rb -n test_yaml_serialize_structure
$ ruby -Itest test/unit/serializing_test.rb -n test_yaml_deserialize_structure
But if I run the deserialization calls from a Rails console the object is not deserialized properly because the class is never required:
$ rails c
ruby-1.9.2-p0 > object = YAML.load_file "#{Rails.root}/tmp/object.yml"
=> #<Syck::Object:0x0000010322ea30 @class="MyModel", @ivars={"id"=>"my model"}>
I know the only problem is that the class is not required because if I require it by hand everything works:
ruby-1.9.2-p0 > require "#{Rails.root}/app/models/my_model"
=> ["MyModel"]
ruby-1.9.2-p0 > object = YAML.load_file "#{Rails.root}/tmp/object.yml"
=> #<MyModel:0x0000010320c8e0 @id="my model">
I have presented only the YAML examples but with Marshal is pretty the same.
Also say that although I'm reproducing the problem in a Rails console originally this problem was turning me crazy in a normal request to my application.
So the question is: How can I deserialize objects in Rails without have to require all my classes by hand?
Thanks
f.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…