2013-04-03 6 views
5

In un'azione di application_controller, se proviamo:YAML - TypeError: non può scaricare il modulo anonimo

p request.env.to_yaml 

sarò ottenuto questo errore:

TypeError: can't dump anonymous module: #<Module:0x007fee26e34ad8> 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:267:in `visit_Module' 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:102:in `accept' 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:447:in `block in dump_ivars' 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:445:in `each' 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:445:in `dump_ivars' 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:124:in `visit_Object' 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:102:in `accept' 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:447:in `block in dump_ivars' 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:445:in `each' 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:445:in `dump_ivars' 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:124:in `visit_Object' 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:102:in `accept' 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:292:in `block in visit_Hash' 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:290:in `each' 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:290:in `visit_Hash' 
    from /Users/twer/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:102:in `accept' 

La mia domanda è: come posso serializzare request.env in yaml?

In realtà, dovevo passare request.env a delayed_job e inviare email, e ho ricevuto questo errore perché delayed_job ha bisogno di serializzare l'oggetto in DB.

+0

Avete testato la mia risposta? ci sono commenti a riguardo? – fotanus

risposta

0

Con il codice physic, può sembrare un po 'strano, ma

request.env.instance_eval "def name; 'some_name'; end" 

potrebbe funzionare. Freddo, canticchia?

3

Il problema è che l'hash request.env ha molti oggetti nidificati (e soprattutto moduli), che non possono essere convertiti in yaml. Il trucco è eliminare quelle parti dell'hash che non possono essere convertite.

tmp_env = request.env.clone 
tmp_env.delete "action_dispatch.routes" 
tmp_env.delete "action_controller.instance" 
tmp_env["action_dispatch.remote_ip"] = tmp_env["action_dispatch.remote_ip"].to_s 
p tmp_env.to_yaml # now it works 

Abbiamo primo clone dell'originale env hash, di non accidentalmente modificarlo. Quindi cancelliamo quelle chiavi dalla nostra copia, che causano errori.

tmp_env["action_dispatch.routes"] contiene un riferimento a un modulo senza nome all'interno di un oggetto ActionDispatch::Routing::RouteSet, che è la causa del tuo errore. È meglio cancellarlo.

tmp_env["action_controller.instance"] contiene un riferimento all'originale env -hash (che non è possibile convertire). Cancellalo.

Infine, tmp_env["action_dispatch.remote_ip"] sembra una stringa (durante l'ispezione), ma è un'istanza ActionDispatch::RemoteIp::GetIp. Contiene un altro riferimento all'originale env hash. Lo convertiamo in una stringa, perché non so se sei interessato a quella chiave in seguito.

Inoltre, è possibile rimuovere molti più tasti per ridurre le dimensioni dell'output di yaml. Tuttavia, questo dovrebbe funzionare senza generare l'errore che hai riscontrato. Una soluzione più snella sarebbe iniziare con un hash vuoto e copiare solo i tasti di cui hai veramente bisogno nel tuo output yaml.

testati con ruby ​​1.9.3 e le rotaie 3.2.13

2

Ecco cosa mi è venuta, in base a esempio di Tessi:

module RequestSerializationHelper 
    ::SerializableRequest = Struct.new(
    :env, 
    :filtered_parameters, 
    :fullpath, 
    :headers, 
    :request_method, 
    :remote_ip 
) 

    ## From http://stackoverflow.com/questions/7604153/rails-2-3-14-how-to-serialise-an-actioncontrollerrequest-object 
    ## with additional modifications 

    # build a serializable Struct that out of the given request object, which looks like a real request 
    def make_request_serializable(request) 
    serializable_request = ::SerializableRequest.new 
    serializable_request.env = request.env.clone 
    serializable_request.filtered_parameters = request.filtered_parameters.clone if request.respond_to? :filtered_parameters 
    serializable_request.fullpath = request.fullpath 
    serializable_request.headers = request.respond_to?(:headers) ? request.headers.clone : {} 
    serializable_request.request_method = request.request_method 

    delete_identified_unserializable_values(serializable_request.env) 
    delete_identified_unserializable_values(serializable_request.headers) 

    # Some jobs want this, so set it after it's been converted to a string in the env 
    serializable_request.remote_ip = serializable_request.env["action_dispatch.remote_ip"] 

    # automatically delete anything left that's non-serializable. If we end up deleting 
    # too much and breaking something, here's where to debug it based on info in warning 
    delete_unidentified_unserializable_values :env, serializable_request.env 
    delete_unidentified_unserializable_values :headers, serializable_request.headers 

    serializable_request 
    end 

    def delete_identified_unserializable_values(hash) 
    hash.delete "async.callback" 
    hash.delete "action_dispatch.backtrace_cleaner" 
    hash.delete "action_dispatch.cookies" 
    hash.delete "action_dispatch.request.accepts" 
    hash.delete "action_dispatch.routes" 
    hash.delete "action_dispatch.logger" 
    hash.delete "action_controller.instance" 
    hash.delete "rack.input" 
    hash.delete "rack.errors" 
    hash.delete "rack.session" 
    hash.delete "rack.session.options" 
    hash["action_dispatch.remote_ip"] = hash["action_dispatch.remote_ip"].to_s 
    hash.delete "warden" 
    hash.delete_if { |key, _| key =~ /^rack-cache/ } 
    end 

    private 

    def delete_unidentified_unserializable_values(hash_name, hash) 
    hash.each do |key, value| 
     begin 
     serialized = value.to_yaml 
     YAML.load(serialized) 
     rescue => e 
     warning = "RequestSerializationHelper: Automatically removing un(re)serializable entry in " + 
      "'#{hash_name}' for key '#{key}' and value '#{value}'. Exception was: '#{e}'" 
     Rails.logger.warn(warning) 
     hash.delete key 
     end 
    end 
    end 
end 
+0

Sembra buono, soprattutto che hai organizzato le cose in un aiutante. – tessi

Problemi correlati