2012-12-06 19 views
9

Wprowadzam funkcję śledzenia papieru w mojej aplikacji rails. Aby to zrobić, serializuję obiekt w YAML. Mam item_at_version metodę, która w zasadzie nie YAML::load(cached_object) - to działa całkiem dobrze, jednak nie mam pojęcia dlaczego, czasami zwraca undefined class/module _class name_. Działa z modelami takimi jak Event, Conversation, Note i wieloma innymi, ale bez żadnego powodu wydaje się, że ten błąd jest zgłaszany w modelach takich jak Dataset, Comment, Student (próbowałem znaleźć dowolny wzór, bez żadnego szczęścia).YAML :: load podnosi niezdefiniowany błąd klasy/modułu

Używam szyn 3.2.8 rubin 1.9.3p327, psych jak YAML silnika (Psych :: Wersja zwraca 1.3.4).

Ps. Kiedy dodaję wymaganie "nazwa_modelu" na górze tego pliku, działa jak czar.

Jakieś pomysły co należy zmienić/dodać uzyskać tej pracy?

Edit: Nie ma dużo kodu, które mogę podzielić:

def item_at_version 
    YAML::load(cached_object) 
end 

Ale może backtrace będzie interesujący:

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

Prawdopodobnie otrzymasz lepszą pomoc, jeśli pokażesz odpowiedni kod lub ślad śladu. – deefour

+0

W moim kodzie nie ma nic magicznego, co nie mam wiele do dodania. Dodałem pełny ślad, może to pomoże. – user1105595

Odpowiedz

12

Podczas korzystania YAML.dump do serializacji obiektu w Ruby, klasa nazwa jest używana jako część znacznika Yaml, aby można było użyć poprawnej klasy podczas ładowania obiektu. Na przykład:

require 'yaml' 

class Foo; end 

puts YAML.dump Foo.new 

produkuje

--- !ruby/object:Foo {} 

Podczas korzystania YAML.load tego łańcucha, Psych wie, co klasa instancji dla rozszeregować obiektu.

Jeśli spróbujesz zadzwonić YAML.load na sznurku yaml określająca klasę, która nie została zdefiniowana, wtedy pojawia się błąd:

require 'yaml' 

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

produkuje:

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

Jest ponieważ Psych musi stworzyć instancję klasy Bar, ale nie ma definicji dostępnej klasy. To tłumaczy, dlaczego przed załadowaniem prac Yamla dodaje się require 'whatever' - teraz Ruby ma zdefiniowaną klasę załadowaną, a więc może utworzyć jej instancję (zauważ, że nie istnieje jednoznaczne połączenie między nazwą klasy a nazwą pliku w Ruby, to tylko konwencja).

zatem rozwiązaniem jest, aby upewnić się, że kiedy jesteś ładowaniu Ruby obiektów z yaml już wymagane jakiekolwiek pliki, które mogą zawierać definicje jakichkolwiek zajęć w tym potencjalnie yaml.

+2

- dziękuję za odpowiedź, ale nadal nie jestem pewien, dlaczego nie działa w szynach. Kiedy dodaję '' 'Bar.new (some:: params)' '' to działa, więc natychmiastowy obiekt _ musi również działać, prawda? – user1105595

+1

@ user1105595 To interesujące. Ma to związek z automatycznym ładowaniem klas Railsów. Kiedy robisz "Bar.new", uruchamia on normalny proces automatycznego ładowania, ale deserializacja z Yaml tego nie robi. Uruchomienie aplikacji w trybie produkcyjnym (lub po prostu z 'cache_classes = true') powinno działać, ponieważ wszystkie klasy będą już załadowane (prawdopodobnie nie chcesz tego robić cały czas). Nie jestem pewien, jakie jest najlepsze rozwiązanie, może być konieczne jawne zażądanie plików w inicjalizatorze lub coś podobnego. – matt

+1

Znalazłem ten raport o błędzie, który odnosi się do tego samego problemu (chodzi o Marszałka, ale metoda 'rb_path_to_class' jest tą samą, która powoduje błąd w Psych) http://bugs.ruby-lang.org/issues/3511 . – matt

2

Matt's Answer zapewnia niezbędne szczegóły.

Ale kiedy zrobić zmiany w kodzie, a następnie wykonać pewne zadania, które de-serializes jakieś dane, bez obciążenia strony (AJAX), to nie jest on z tego samego błędu.

Lepiej używać require_dependency niż require, aby automatycznie ładować zmiany.

W przypadku modułu (nie testowano przy użyciu) i deklasyfikacji przy użyciu YAML, można także utworzyć instancję modułu przed odseparowaniem przy pomocy require, aby rozwiązać problem. See here.

Źródło: SO answer i Psych issue report in Github

P.S: Ten problem nie ustępuje tylko w rozwoju, jak config.cache_classes jest umożliwienie produkcji.

1

Zmiana na Matt's answer. Zamiast rozwiązania opartego na czystym hashu (którego zespół Psych nie wydaje się być zainteresowany), zmodyfikuj ciąg nagłówka, aby usunąć klasyfikację obiektu. Zrobiłem to po prostu za pomocą poniższego kodu.

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

To może zakończyć się niepowodzeniem (nie wiem), czy strumień wejściowy składa się z kilku dokumentów z różnych klasyfikatorów obiektów (Nie wiem, czy to jest jeszcze ważny).

Powiązane problemy