如何将此哈希转换为可用的JSON?

时间:2014-04-07 11:26:05

标签: ruby-on-rails ruby json internet-explorer hash

IE10返回的参数看起来像是对JSON的双重转换:

=> {"{\"statementId\":"=>
  {"\"b3dsecret9-bsecret741-23secreta806c\""=>
    {",\"Content-Type\":"=>
      {"\"application/json\""=>
        {",\"content\":"=>
          {"\"{\\\"context\\\":{\\\"registration\\\":\\\"27\\\",\\\"contextActivities\\\":{\\\"parent\\\":{\\\"id\\\":\\\"6LHIJumrnmV_course_id\\\"},\\\"grouping\\\":{\\\"id\\\":\\\"6LHIJumrnmV_course_id\\\"}}},\\\"actor\\\":213,\\\"verb\\\":\\\"attempted\\\",\\\"object\\\":{\\\"id\\\":\\\"6LHIJumrnmV_course_id\\\",\\\"definition\\\":{\\\"name\\\":{\\\"und\\\":\\\"\\\"},\\\"type\\\":\\\"Course\\\",\\\"description\\\":{\\\"und\\\":\\\"\\\"}}}}\""=>
            {",\"registration\":"=>
              {"\"27\""=>
                {",\"AWSAccessKeyId\":"=>
                  {"\"secretIAIVsecretPHsecretQ\""=>
                    {",\"Signature\":"=>
                      {"\"PJ /OW K5secretasyXsecret5A"=>
                        "\"],\"Expires\":[\"1396873090\"],\"Authorization\":[\"\"]}"}}}}}}}}}}},
 "method"=>"PUT",
 "controller"=>"quizzes",
 "action"=>"statements"}

IE Edge,Safari,Chrome和Firefox会像这样返回我的参数:

=> {"registration"=>["27"],
 "Content-Type"=>["application/json"],
 "Signature"=>["secretkqPJGPEsecret01ksecret"],
 "AWSAccessKeyId"=>["Asecret6secretPHsecretQ"],
 "statementId"=>["5919c4f4-b71c-40dd-81dc-ab63cfc824bd"],
 "Expires"=>["1396873699"],
 "Authorization"=>[""],
 "content"=>
  ["{\"object\":{\"definition\":{\"type\":\"Course\",\"name\":{\"und\":\"\"},\"description\":{\"und\":\"\"}},\"id\":\"6LHIJumrnmV_course_id\"},\"verb\":\"attempted\",\"context\":{\"registration\":\"27\",\"contextActivities\":{\"parent\":{\"id\":\"6LHIJumrnmV_course_id\"},\"grouping\":{\"id\":\"6LHIJumrnmV_course_id\"}}},\"actor\":213}"],
 "method"=>"PUT",
 "controller"=>"quizzes",
 "action"=>"statements",
 "quiz"=>{}

所以我的代码可以方便地解析这个:

content = params[:content] || params['content']
response = JSON.parse(content.first)

并且presto!我有一个可行的内容。但是,首先提到的Hash,我不知道如何转换它。我是否应该考虑使用match / gsub技术来删除所有那些邪恶的正斜杠?有没有办法将其破译成看起来像我后一个哈希的东西?

2 个答案:

答案 0 :(得分:1)

从您的回答开始,我会使用escape_utils gem解析key

require 'escape_utils'

def nested_hash_value(obj,key)
  # nested_hash_value(params, ",\"content\":")
  if obj.respond_to?(:key?) && obj.key?(key)
    obj[key]
  elsif obj.respond_to?(:each)
    r = nil
    obj.find{ |*a| r=nested_hash_value(a.last,key) }
    r
  end
end    

extract  = nested_hash_value(params, ",\"content\":")
key      = extract.keys.first
response = JSON.parse EscapeUtils.unescape_javascript(key).gsub(/^"|"$/,'')

这避免了使用邪恶的eval事物。

更一般地说,我认为你应该以这种方式建立你的处理:

def smell_of_ie_weirdness?
  # Detects whether the request seems like the one sent by IE 10,
  # something like params keys formatting checking etc.
end

def extracted_response
  if smell_of_ie_weirdness?
    # Do weird stuff
    extract_response_for_weird_ie
  else
    # Be clean and polite
    extract_response
  end
end

答案 1 :(得分:0)

这给了我一个答案..它不是最好的。这肯定是一个黑客。但我觉得这是我唯一得到的东西。

def nested_hash_value(obj,key)
  # nested_hash_value(params, ",\"content\":")
  if obj.respond_to?(:key?) && obj.key?(key)
    obj[key]
  elsif obj.respond_to?(:each)
    r = nil
    obj.find{ |*a| r=nested_hash_value(a.last,key) }
    r
  end
end    


extract      = nested_hash_value(params, ",\"content\":")
key          = extract.keys.first
decoded_hash = key.to_s.gsub(/\\/,'').gsub(/\"/,"'").gsub(/'$|^'/,'').gsub(':','=>')
response     = eval decoded_hash      

如果我在两个输出之间进行比较==,则返回true

然后我把它全部放在救援区......

begin
  content = params[:content] || params['content']
  response = JSON.parse(content.first)
rescue
  perform_fd_up_IE_fixer # :)
end