Trying to deserialize a very simple object using YAML.load
or Marshal.load
produces a corru
To automatically require classes on YAML loading in the manner @fguillen suggests is elegant, I wrote this short monkey-patch.
It simply attempts to require_dependency any class the Psych ToRuby class resolves to classes.
Works for me in a serialised Active Record that stores a custom class instance, YMMV.
module Psych::Visitors
ToRuby.class_eval do
alias :resolve_class_without_autoload :resolve_class
def resolve_class klassname
begin
require_dependency klassname.underscore
rescue NameError, LoadError
end
resolve_class_without_autoload klassname
end
end
end
I described this "issue" on GitHub: https://github.com/rails/rails/issues/1585
As far as I know, both YAML and Marshal do not make use of the Rails autoloader. You must go ahead and pre-load any classes that might need to be deserialized.
It's a bit if a fuss, especially in the development environment where almost nothing is loaded before it is needed.
I had to adapt @ben-patterson's answer a bit to make it work (using Rails 5.0.2):
module Psych::Visitors
ToRuby.class_eval do
def resolve_class(klassname)
begin
class_loader.load klassname
rescue ArgumentError
require_dependency klassname.underscore
klassname.constantize
end
end
end
end
Well, after read @tadman and a bunch of answers I have received in the spanish ror mailing list [1] I have collected a few hot tips when you have to deal with Ruby deserializing and class loading in Rails:
Super fast solution
Use config.cache_classes = true
in your development.rb
but you will lost the class auto-refreshing.
Better solution
Require all the classes that are gonna be deserialized but not with require
but with require_dependency
[2] so in development environment the class auto-refreshing will remain working.
Elegant solution
Monkey-patch the YAML and the Marshal gem to tell them to call require_dependency
when they find a non-defined class to deserialize.
And @Xavi has sent me a proposition of monkey-patch Marshal
(he says he wrote it on the air and it is not tested so use it in your own risk) [3]