2012-12-06 1 views
9

私は私のレールアプリでペーパートレイルのような機能を実装しています。これを行うために、私はYAMLのオブジェクトをシリアル化しています。私はitem_at_versionメソッドを持っていますが、これは基本的にYAML::load(cached_object)ですが、これはかなりうまくいきますが、理由はわかりません。時にはundefined class/module _class name_を返します。 イベント、会話、ノートなどのモデルで動作しますが、理由はありませんが、Dataset、Comment、Studentなどのモデルではエラーが発生しているようです)。YAML :: loadは未定義のクラス/モジュールエラーを発生させます

私はrails 3.2.8、ruby 1.9.3p327、psychをYAML Engineとして使用しています(Psych :: Versionは1.3.4を返します)。

ps。そのファイルの上にrequire 'model_name'を追加すると、それは魅力のように機能します。

このアイデアを変更するにはどうすればよいですか?

編集: あり、私は共有することができます何も多くのコードません:

def item_at_version 
    YAML::load(cached_object) 
end 

は、しかし、おそらくバックトレースは興味深いものになるだろう:

~/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/psych/visitors/to_ruby.rb:312:in `path2class' 
~/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/psych/visitors/to_ruby.rb:312:in `resolve_class' 
~/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/psych/visitors/to_ruby.rb:219:in `visit_Psych_Nodes_Mapping' 
~/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/psych/visitors/visitor.rb:15:in `visit' 
~/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/psych/visitors/visitor.rb:5:in `accept' 
~/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/psych/visitors/to_ruby.rb:20:in `accept' 
~/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/psych/visitors/to_ruby.rb:238:in `visit_Psych_Nodes_Document' 
~/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/psych/visitors/visitor.rb:15:in `visit' 
~/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/psych/visitors/visitor.rb:5:in `accept' 
~/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/psych/visitors/to_ruby.rb:20:in `accept' 
~/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/psych/nodes/node.rb:35:in `to_ruby' 
~/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/psych.rb:128:in `load' 
app/models/history_version.rb:7:in `item_at_version' 
app/controllers/history_controller.rb:8:in `show' 
actionpack (3.2.8) lib/action_controller/metal/implicit_render.rb:4:in `send_action' 
actionpack (3.2.8) lib/abstract_controller/base.rb:167:in `process_action' 
actionpack (3.2.8) lib/action_controller/metal/rendering.rb:10:in `process_action' 
actionpack (3.2.8) lib/abstract_controller/callbacks.rb:18:in `block in process_action' 
activesupport (3.2.8) lib/active_support/callbacks.rb:502:in `_run__1697733322876708236__process_action__1122943786273335015__callbacks' 
activesupport (3.2.8) lib/active_support/callbacks.rb:405:in `__run_callback' 
activesupport (3.2.8) lib/active_support/callbacks.rb:385:in `_run_process_action_callbacks' 
activesupport (3.2.8) lib/active_support/callbacks.rb:81:in `run_callbacks' 
actionpack (3.2.8) lib/abstract_controller/callbacks.rb:17:in `process_action' 
actionpack (3.2.8) lib/action_controller/metal/rescue.rb:29:in `process_action' 
actionpack (3.2.8) lib/action_controller/metal/instrumentation.rb:30:in `block in process_action' 
activesupport (3.2.8) lib/active_support/notifications.rb:123:in `block in instrument' 
activesupport (3.2.8) lib/active_support/notifications/instrumenter.rb:20:in `instrument' 
activesupport (3.2.8) lib/active_support/notifications.rb:123:in `instrument' 
actionpack (3.2.8) lib/action_controller/metal/instrumentation.rb:29:in `process_action' 
actionpack (3.2.8) lib/action_controller/metal/params_wrapper.rb:207:in `process_action' 
activerecord (3.2.8) lib/active_record/railties/controller_runtime.rb:18:in `process_action' 
actionpack (3.2.8) lib/abstract_controller/base.rb:121:in `process' 
actionpack (3.2.8) lib/abstract_controller/rendering.rb:45:in `process' 
actionpack (3.2.8) lib/action_controller/metal.rb:203:in `dispatch' 
actionpack (3.2.8) lib/action_controller/metal/rack_delegation.rb:14:in `dispatch' 
actionpack (3.2.8) lib/action_controller/metal.rb:246:in `block in action' 
actionpack (3.2.8) lib/action_dispatch/routing/route_set.rb:73:in `call' 
actionpack (3.2.8) lib/action_dispatch/routing/route_set.rb:73:in `dispatch' 
actionpack (3.2.8) lib/action_dispatch/routing/route_set.rb:36:in `call' 
journey (1.0.4) lib/journey/router.rb:68:in `block in call' 
journey (1.0.4) lib/journey/router.rb:56:in `each' 
journey (1.0.4) lib/journey/router.rb:56:in `call' 
actionpack (3.2.8) lib/action_dispatch/routing/route_set.rb:600:in `call' 
actionpack (3.2.8) lib/action_dispatch/middleware/best_standards_support.rb:17:in `call' 
rack (1.4.1) lib/rack/etag.rb:23:in `call' 
rack (1.4.1) lib/rack/conditionalget.rb:25:in `call' 
actionpack (3.2.8) lib/action_dispatch/middleware/head.rb:14:in `call' 
actionpack (3.2.8) lib/action_dispatch/middleware/params_parser.rb:21:in `call' 
actionpack (3.2.8) lib/action_dispatch/middleware/flash.rb:242:in `call' 
rack (1.4.1) lib/rack/session/abstract/id.rb:205:in `context' 
rack (1.4.1) lib/rack/session/abstract/id.rb:200:in `call' 
actionpack (3.2.8) lib/action_dispatch/middleware/cookies.rb:339:in `call' 
activerecord (3.2.8) lib/active_record/query_cache.rb:64:in `call' 
activerecord (3.2.8) lib/active_record/connection_adapters/abstract/connection_pool.rb:473:in `call' 
actionpack (3.2.8) lib/action_dispatch/middleware/callbacks.rb:28:in `block in call' 
activesupport (3.2.8) lib/active_support/callbacks.rb:405:in `_run__2589517259026276185__call__1369641113040304056__callbacks' 
activesupport (3.2.8) lib/active_support/callbacks.rb:405:in `__run_callback' 
activesupport (3.2.8) lib/active_support/callbacks.rb:385:in `_run_call_callbacks' 
activesupport (3.2.8) lib/active_support/callbacks.rb:81:in `run_callbacks' 
actionpack (3.2.8) lib/action_dispatch/middleware/callbacks.rb:27:in `call' 
actionpack (3.2.8) lib/action_dispatch/middleware/reloader.rb:65:in `call' 
actionpack (3.2.8) lib/action_dispatch/middleware/remote_ip.rb:31:in `call' 
bugsnag (1.2.5) lib/bugsnag/rack.rb:35:in `call' 
actionpack (3.2.8) lib/action_dispatch/middleware/debug_exceptions.rb:16:in `call' 
actionpack (3.2.8) lib/action_dispatch/middleware/show_exceptions.rb:56:in `call' 
railties (3.2.8) lib/rails/rack/logger.rb:26:in `call_app' 
railties (3.2.8) lib/rails/rack/logger.rb:16:in `call' 
quiet_assets (1.0.1) lib/quiet_assets.rb:20:in `call_with_quiet_assets' 
actionpack (3.2.8) lib/action_dispatch/middleware/request_id.rb:22:in `call' 
rack (1.4.1) lib/rack/methodoverride.rb:21:in `call' 
rack (1.4.1) lib/rack/runtime.rb:17:in `call' 
activesupport (3.2.8) lib/active_support/cache/strategy/local_cache.rb:72:in `call' 
rack (1.4.1) lib/rack/lock.rb:15:in `call' 
actionpack (3.2.8) lib/action_dispatch/middleware/static.rb:62:in `call' 
railties (3.2.8) lib/rails/engine.rb:479:in `call' 
railties (3.2.8) lib/rails/application.rb:223:in `call' 
railties (3.2.8) lib/rails/railtie/configurable.rb:30:in `method_missing' 
~/Library/Application Support/Pow/Versions/0.4.0/node_modules/nack/lib/nack/server.rb:147:in `handle' 
~/Library/Application Support/Pow/Versions/0.4.0/node_modules/nack/lib/nack/server.rb:99:in `rescue in block (2 levels) in start' 
~/Library/Application Support/Pow/Versions/0.4.0/node_modules/nack/lib/nack/server.rb:96:in `block (2 levels) in start' 
~/Library/Application Support/Pow/Versions/0.4.0/node_modules/nack/lib/nack/server.rb:86:in `each' 
~/Library/Application Support/Pow/Versions/0.4.0/node_modules/nack/lib/nack/server.rb:86:in `block in start' 
~/Library/Application Support/Pow/Versions/0.4.0/node_modules/nack/lib/nack/server.rb:66:in `loop' 
~/Library/Application Support/Pow/Versions/0.4.0/node_modules/nack/lib/nack/server.rb:66:in `start' 
~/Library/Application Support/Pow/Versions/0.4.0/node_modules/nack/lib/nack/server.rb:13:in `run' 
~/Library/Application Support/Pow/Versions/0.4.0/node_modules/nack/bin/nack_worker:4:in `<main>' 
+0

関連するコードやバックトレースを表示すると、より良いヘルプを得ることができます。 – deefour

+0

私のコードには何も魔法がありません。私にはあまり追加する必要はありません。私は完全なバックトレースを追加しました。 – user1105595

答えて

12

あなたは、Rubyでクラスをオブジェクトをシリアル化するためにYAML.dumpを使用nameはYamlタグの一部として使用されるため、オブジェクトをロードするときに正しいクラスを使用できます。たとえば:

require 'yaml' 

class Foo; end 

puts YAML.dump Foo.new 

は、あなたがその文字列にYAML.loadを使用すると、サイコは、デシリアライズされたオブジェクトのインスタンス化にどのようなクラスを知っている

--- !ruby/object:Foo {} 

生成します。

あなたが定義されていないクラスを指定YAML文字列にYAML.loadを呼び出そうとした場合、その後、あなたがエラーを取得します:

require 'yaml' 

# No Bar class has been defined 
YAML.load '--- !ruby/object:Bar {}' 

が生成する:

/Users/matt/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/psych/visitors/to_ruby.rb:312:in `path2class': undefined class/module Bar (ArgumentError) 
    from /Users/matt/.rvm/rubies/ruby-1.9.3-p327/lib/ruby/1.9.1/psych/visitors/to_ruby.rb:312:in `resolve_class' 
... 

これは、 PsychはクラスBarのインスタンスを作成する必要があるため、利用可能なクラスの定義はありません。これでYamlが読み込まれる前にrequire 'whatever'を追加する理由が説明されています - Rubyはロードされたクラスの定義を持っていますので、そのインスタンスを作成できます(Rubyではクラス名とファイル名の間に明確なリンクはありません)。

したがって、YamlからRubyオブジェクトをロードするときに、そのYamlに潜在的に存在するクラスの定義を含むファイルが必要であることを確認することです。

+2

- あなたの答えをありがとう、しかし、私はまだこれがレールで動作していない理由はわかりません。 '' 'Bar.new(some::params)' 'を追加すると、オブジェクトがインスタンス化されても動作するのでしょうか? – user1105595

+1

@ user1105595それは面白いです。これはRailsのクラスの自動ロードと関係があります。 'Bar.new'を実行すると、通常の自動ロードプロセスが起動されますが、Yamlから逆シリアル化されません。すべてのクラスが既にロードされているので、あなたは実稼働環境で(または単に 'cache_classes = true'を使って)あなたのアプリケーションを実行します(おそらくそれをしたくないかもしれません)。私は最良の解決策が何であるか分かりません。ファイルをイニシャライザなどで明示的に要求する必要があるかもしれません。 – matt

+1

同じ問題を参照しているこのバグレポートを見つけました(これはマーシャルのことですが、 'rb_path_to_class'メソッドはPsychのエラーの原因と同じものです)http://bugs.ruby-lang.org/issues/3511 。 – matt

2

Matt's Answerは、必要な詳細を提供します。

しかし、私はコードの変更を行い、その後いくつかのタスクを行うと、ページの読み込みなしで(AJAXで)いくつかのデータをデシリアライズすると、同じエラーで失敗します。

require_dependencyrequireよりも使用して変更を自動読み込みする方が良いです。

モジュールの場合(classでテストされていない)、YAMLを使用してデシリアライズする場合は、モジュールをデシリアライズしてrequireでインスタンス化して問題を解決することもできます。 See here.

出典:SO answerPsych issue report in Github

P.S:config.cache_classesは生産に有効であるとして、この問題は開発中持続します。

1

Matt's answerに修正されています。純粋なハッシュに基づくソリューション(Psychチームはこれに関心がないようです)の代わりに、オブジェクトの分類を取り除くためにヘッダー文字列を変更します。私は次のコードでこれを単純に行いました。

yamltext = File.read("somefile","r") 
yamltext.sub!(/^--- \!.*$/,'---') 
hash = YAML.load(yamltext) 

これは、入力ストリームが異なるオブジェクト分類といくつかのドキュメントで構成されている場合は(私はそれでも有効かどう知らない)(私は知りません)失敗することがあります。