Rails doesn't load classes on deserializing YAML/Marshal objects

前端 未结 5 826
离开以前
离开以前 2020-12-16 02:32
  • Rails: 3.0.3
  • Ruby: 1.9.2

Trying to deserialize a very simple object using YAML.load or Marshal.load produces a corru

相关标签:
5条回答
  • 2020-12-16 02:35

    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
    
    0 讨论(0)
  • 2020-12-16 02:37

    I described this "issue" on GitHub: https://github.com/rails/rails/issues/1585

    0 讨论(0)
  • 2020-12-16 02:45

    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.

    0 讨论(0)
  • 2020-12-16 02:54

    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
    
    0 讨论(0)
  • 2020-12-16 02:55

    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]

    • [1] http://lists.simplelogica.net/pipermail/ror-es/2011-January/024787.html
    • [2] http://apidock.com/rails/ActiveSupport/Dependencies/Loadable/require_dependency
    • [3] http://lists.simplelogica.net/pipermail/ror-es/2011-January/024796.html
    0 讨论(0)
提交回复
热议问题