to_json没有将特殊字符转换为unicode样式

Ing*_*ngo 10 ruby json ruby-on-rails

将哈希值转换为json字符串时,我遇到了特殊字符的问题.

使用Ruby 2.0/Rails 3.2.21,一切正常,也就是说,

puts "“".to_json
#"\u201c"
Run Code Online (Sandbox Code Playgroud)

但是使用Ruby 2.3.0/Rails 4.2.5.1我得到了

puts "“".to_json
#"“"
Run Code Online (Sandbox Code Playgroud)

有没有办法强制Ruby 2.3.0将特殊字符转换为unicode样式字符串(\uXXXX)?

备注:

请注意,在Ruby 2.3/Rails 4中,我们得到了

"“".to_json.bytesize == 5 #true
Run Code Online (Sandbox Code Playgroud)

但是,在2.0中我们得到了

"“".to_json.bytesize == 8 #true
Run Code Online (Sandbox Code Playgroud)

很明显,字符串本身是不同的,而不是不同的输出格式.

Ale*_*kin 6

我❤Rails(开个玩笑.)

在Rails3中,有一种令人捧心的方法来破坏JSON中的UTF-8.Rails4,谢谢DHH,摆脱了这个缺点.

因此,无论是否需要时间倒退机器,最简单的方法是monkeypatch ::ActiveSupport::JSON::Encoding#escape:

module ::ActiveSupport::JSON::Encoding
  def self.escape(string)
    if string.respond_to?(:force_encoding)
      string = string.encode(::Encoding::UTF_8, :undef => :replace)
                     .force_encoding(::Encoding::BINARY)
    end
    json = string.
            gsub(escape_regex) { |s| ESCAPED_CHARS[s] }.
            gsub(/([\xC0-\xDF][\x80-\xBF]|
                   [\xE0-\xEF][\x80-\xBF]{2}|
                   [\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s|
            s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\\\u\&')
          }
    json = %("#{json}")
    json.force_encoding(::Encoding::UTF_8) if json.respond_to?(:force_encoding)
    json
  end
end
Run Code Online (Sandbox Code Playgroud)

更强大的解决方案是破坏结果:

class String
  def rails3_style
    string = encode(::Encoding::UTF_8, :undef => :replace).
               force_encoding(::Encoding::BINARY)
    json = string.
      gsub(/([\xC0-\xDF][\x80-\xBF]|
             [\xE0-\xEF][\x80-\xBF]{2}|
             [\xF0-\xF7][\x80-\xBF]{3})+/nx) { |s| 
      s.unpack("U*").pack("n*").unpack("H*")[0].gsub(/.{4}/n, '\\\\u\&')
    }   
    json = %("#{json}")
    json.force_encoding(::Encoding::UTF_8) if json.respond_to?(:force_encoding)
    json
  end 
end

puts "“".to_json.rails3_style
#? "\u201c"
Run Code Online (Sandbox Code Playgroud)

我几乎无法理解为什么有人可能会故意这样做,但解决方案就在这里.