Railsは、ヤムル/マーシャルオブジェクトの降下にクラスをロードしません

StackOverflow https://stackoverflow.com/questions/4705867

質問

  • レール:3.0.3
  • ルビー:1.9.2

非常にシンプルなオブジェクトを使用して脱色しようとしています YAML.load また Marshal.load 属するクラスは、脱出プロセスでは必要ないため、破損したオブジェクトを生成します。

例:

# 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

このコードを使用すると、エラーなしでこのシェルコンソールセッションを実行できます。

$ ruby -Itest test/unit/serializing_test.rb -n test_yaml_serialize_structure
$ ruby -Itest test/unit/serializing_test.rb -n test_yaml_deserialize_structure

しかし、私が実行した場合 脱isionization Calls Railsコンソールから、クラスが必要ないため、オブジェクトは適切に脱色されません。

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

私は唯一の問題は、クラスが必要でないということです。

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の例だけを提示しましたが、元sの場合はかなり同じです。

また、私は問題を再現しているが Railsコンソール もともとこの問題は、私のアプリケーションへの通常の要求で私を夢中にさせていました。

質問は次のとおりです。 すべてのクラスを手作業で要求することなく、レールのオブジェクトをゆるくするにはどうすればよいですか?

ありがとう

f。

役に立ちましたか?

解決

まあ、読んだ後 @tadman そして、私がスペインのRORメーリングリストで受け取ったたくさんの回答[1] Rubyの脱皮とクラスの積み込みに対処する必要があるときに、いくつかのホットなヒントを収集しました。

超高速ソリューション

使用する config.cache_classes = true あなたの中で development.rb しかし、あなたはクラスの自動再洗浄を失うでしょう。

より良い解決策

脱色されるが、ではないすべてのクラスが必要です require しかし、と require_dependency2]だから 発達 環境クラスの自動再洗浄は機能し続けます。

エレガントなソリューション

モンキーパッチ Yaml そしてその 元s 彼らに電話をするように言う宝石 require_dependency 彼らが脱気になるために定義されていないクラスを見つけたとき。

@xavi モンキーパッチの提案を送ってくれました Marshal (彼はそれを空中に書いたが、それはテストされていないので、あなた自身の責任でそれを使用してください)[3

他のヒント

この「問題」をGitHubで説明しました。 https://github.com/rails/rails/issues/1585

YAMLロードのクラスを自動的に必要とするには @fguillen 提案はエレガントで、私はこの短いサルパッチを書きました。

それは単に_依存を要求しようとします。クラスは、サイケルビークラスがクラスに解決するクラスです。

カスタムクラスインスタンス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

私はそれを機能させるために @Ben-Pattersonの答えを少し適応させなければなりませんでした(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

私の知る限り、Yamlと元sの両方がRails Autoloaderを利用していません。先に進んで、脱色する必要がある可能性のあるクラスを事前ロードする必要があります。

特に、必要になる前にほとんど何もロードされていない開発環境では、大騒ぎの場合は少しです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top