[英]YAML - TypeError: can't dump anonymous module
在application_controller的一個動作中,如果我們嘗試:
p request.env.to_yaml
我會收到這個錯誤:
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'
我的問題是:如何將request.env
序列化為yaml?
實際上,我應該將request.env傳遞給delayed_job並發送電子郵件,我收到此錯誤,因為delayed_job需要將對象序列化為DB。
問題是,request.env哈希有很多嵌套對象(尤其是模塊),無法轉換為yaml。 訣竅是刪除無法轉換的哈希部分。
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
我們首先克隆原始的env
哈希,以免意外修改它。 然后我們從我們的副本中刪除這些鍵,這會導致錯誤。
tmp_env["action_dispatch.routes"]
包含對ActionDispatch::Routing::RouteSet
對象中未命名模塊的引用,這是導致錯誤的原因。 我們最好刪除它。
tmp_env["action_controller.instance"]
包含對原始env
-hash的引用(我們無法轉換)。 刪除它。
最后tmp_env["action_dispatch.remote_ip"]
看起來像一個字符串(在檢查它時),但它是一個ActionDispatch::RemoteIp::GetIp
實例。 它包含對原始env
哈希的另一個引用。 我們將其轉換為字符串,因為我不知道您以后是否對該密鑰感興趣。
此外,您可以刪除更多的鍵來減少您的yaml輸出的大小。 但是,這應該可以工作而不會拋出您遇到的錯誤。 更精簡的解決方案是從空Hash開始,只復制您在yaml輸出中真正需要的鍵。
用ruby 1.9.3和rails 3.2.13測試
基於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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.