Railsは、ヤムル/マーシャルオブジェクトの降下にクラスをロードしません
-
11-10-2019 - |
質問
- レール: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_dependency
2]だから 発達 環境クラスの自動再洗浄は機能し続けます。
エレガントなソリューション
モンキーパッチ 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を利用していません。先に進んで、脱色する必要がある可能性のあるクラスを事前ロードする必要があります。
特に、必要になる前にほとんど何もロードされていない開発環境では、大騒ぎの場合は少しです。