Rails不会在反序列化YAML / Marshal对象上加载类 [英] Rails doesn't load classes on deserializing YAML/Marshal objects

查看:120
本文介绍了Rails不会在反序列化YAML / Marshal对象上加载类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


  • 轨距:3.0.3

  • Ruby:1.9.2

尝试使用 YAML.load Marshal.load 反序列化一个非常简单的对象会产生损坏的对象,因为

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.

示例:

# 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

使用以下代码,我们可以运行此Shell控制台会话而不会出现任何错误:

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

但是,如果我从Rails控制台运行反序列化调用,则该对象不会正确反序列化,因为该类永远不会必需:

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"> 

我仅介绍了YAML示例,但与Marshal大致相同。

I have presented only the YAML examples but with Marshal is pretty the same.

也可以说,尽管我最初是在 Rails控制台中重现该问题,但这个问题使我对应用程序的正常请求发疯了。

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.

所以问题是:如何在Rails中反序列化对象而不必手动要求所有类?

谢谢

f。

推荐答案

好吧,在阅读 @tadman 后,我在西班牙语ror邮件列表中收到了一堆答案[1]当您不得不处理Ruby反序列化和类加载时,我收集了一些热门提示在Rails中:

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:

超级快速解决方案

使用 config.cache_classes = true 在您的 development.rb 中,但是您将丢失类自动刷新。

Use config.cache_classes = true in your development.rb but you will lost the class auto-refreshing.

更好的解决方案

要求所有要反序列化的类,但不需要 require 但具有 require_dependency [2],因此在开发环境中,类自动刷新将继续工作。

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.

优雅的解决方案

用猴子修补 YAML Marshal 宝石,告诉他们在找到后需要调用 require_dependency

Monkey-patch the YAML and the Marshal gem to tell them to call require_dependency when they find a non-defined class to deserialize.

@Xavi 向我发送了一个关于猴子补丁 Marshal的命题(他说他是在空中写的,未经测试,请您自担风险)[3]

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

这篇关于Rails不会在反序列化YAML / Marshal对象上加载类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆