2012-12-06 6 views
9

Ich implementiere Papierspur wie Feature in meiner Rails App. Um dies zu tun, bin ich serialisieren Objekt in YAML. Ich habe item_at_version Methode, die im Grunde funktioniert YAML::load(cached_object) - das funktioniert ziemlich gut, aber ich habe keine Ahnung warum, manchmal gibt es undefined class/module _class name_. Es funktioniert mit Modellen wie Event, Conversation, Note und vielen mehr, aber ohne Grund scheint es diesen Fehler für Modelle wie Dataset, Kommentar, Student (ich habe versucht, irgendein Muster dafür zu finden, ohne Glück).YAML :: load löst undefinierten Klassen-/Modulfehler

Ich benutze Schienen 3.2.8, Ruby 1.9.3p327, psych als YAML Engine (Psych :: Version gibt 1.3.4 zurück).

Ps. Wenn ich 'model_name' über diese Datei hinzufüge, funktioniert es wie ein Zauber.

Irgendwelche Ideen, was soll ich ändern/hinzufügen, damit das funktioniert?

Edit: Es gibt keine viel Code, die ich teilen kann:

def item_at_version 
    YAML::load(cached_object) 
end 

Aber vielleicht würde Backtrace interessant sein:

~/.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

Sie erhalten wahrscheinlich bessere Hilfe, wenn Sie relevanten Code oder ein Backtrace anzeigen. – deefour

+0

In meinem Code ist nichts Magisches, und ich habe nicht viel hinzuzufügen. Ich habe einen vollständigen Backtrace hinzugefügt, vielleicht kann das helfen. – user1105595

Antwort

12

Wenn Sie YAML.dump verwenden, um ein Objekt in Ruby, die Klasse zu serialisiert name wird als Teil des Yaml-Tags verwendet, damit beim Laden des Objekts die korrekte Klasse verwendet werden kann. Zum Beispiel:

require 'yaml' 

class Foo; end 

puts YAML.dump Foo.new 

produziert

--- !ruby/object:Foo {} 

Wenn Sie YAML.load auf dieser Zeichenkette verwenden, weiß Psych, welche Klasse für die entserialisierten Objekt zu instanziiert.

Wenn Sie versuchen, YAML.load auf einem Yaml Zeichenfolge aufzurufen, die eine Klasse gibt, die noch nicht definiert wurde, dann werden Sie den Fehler:

require 'yaml' 

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

produziert:

/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' 
... 

Dies ist weil Psych eine Instanz der Klasse Bar erstellen muss, aber die Definition der Klasse nicht verfügbar ist. Dies erklärt, warum das Hinzufügen von require 'whatever' vor dem Laden der Yaml funktioniert - jetzt Ruby hat die Definition der Klasse geladen und kann so eine Instanz davon erstellen (beachten Sie, dass es in Ruby keine definitive Verbindung zwischen Klassenname und Dateiname gibt, es ist nur Konvention).

Die Lösung besteht also darin, sicherzustellen, dass Sie beim Laden von Ruby-Objekten aus Yaml bereits alle Dateien benötigt haben, die möglicherweise Definitionen von Klassen in diesem Yaml enthalten.

+2

- danke für deine Antwort, aber ich bin mir immer noch nicht sicher, warum das nicht in Schienen funktioniert. Wenn ich '' 'Bar.new (einige:: params)' '' es funktioniert, so instantinating object_should_ funktioniert auch, oder? – user1105595

+1

@ user1105595 Das ist interessant. Es geht um das Autoloading von Klassen durch Rails. Wenn Sie "Bar.new" ausführen, löst dies den normalen Autoloading-Prozess aus, das Deserialisieren von Yaml jedoch nicht. Wenn Sie Ihre App in der Produktion ausführen (oder nur mit 'cache_classes = true'), sollte es funktionieren, da alle Klassen bereits geladen sind (Sie wollen das wahrscheinlich nicht immer machen). Ich bin nicht sicher, was die beste Lösung ist, müssen Sie möglicherweise nur explizit die Dateien in einem Initialisierer oder etwas erfordern. – matt

+1

Ich habe diesen Fehlerbericht gefunden, der sich auf dasselbe Problem bezieht (es handelt von Marshal, aber die Methode 'rb_path_to_class' ist dieselbe, die den Fehler in Psych verursacht) http://bugs.ruby-lang.org/issues/3511 . – matt

2

Matt's Answer liefert notwendige Details.

Aber wenn ich Änderungen im Code und dann eine Aufgabe, die einige Daten de-serialisiert, ohne Seite laden (in AJAX) dann scheitert es mit demselben Fehler.

Es ist besser, require_dependency als require zu verwenden, um Ihre Änderungen automatisch zu laden.

Im Falle eines Moduls (nicht getestet mit class) und einer De-Serialisierung mit YAML können Sie Ihr Modul vor dem Deserialisieren mit require instanziieren, um das Problem zu beheben. See here.

Quelle: SO answer und Psych issue report in Github

P. S: Dieses Problem weiterhin besteht nur in der Entwicklung als config.cache_classes ist in der Produktion zu ermöglichen.

1

Änderung zu Matt's answer. Anstelle einer reinen Hash-basierten Lösung (die das Psych-Team anscheinend nicht interessiert), modifizieren Sie den Header-String, um die Objektklassifizierung zu entfernen. Ich habe das einfach mit folgendem Code gemacht.

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

Dies könnte scheitern (ich weiß nicht), wenn der Eingangsstrom mit unterschiedlichem Objekt Klassifizierer aus mehreren Dokumenten besteht (ich weiß nicht, ob das überhaupt gültig ist).

Verwandte Themen