阻止字符串在Ruby on Rails哈希中被编码

3
我试图不对哈希中的字符串进行JSON序列化,因为它已经被转义过了。
阅读处理PORO的方法时,需要覆盖 `as_json`。所以我将字符串包装到另一个对象中。但是由于我只处理一个字符串,当我返回该对象时会导致 `堆栈级别太深` 的错误。如果我返回已编码的字符串,则会显然地尝试对其进行转义。activesupport-6.0.3.2/lib/active_support/json/encoding.rb
      def jsonify(value)
        case value
        when String
          EscapedString.new(value)
        when Numeric, NilClass, TrueClass, FalseClass
          value.as_json
        when Hash
          Hash[value.map { |k, v| [jsonify(k), jsonify(v)] }]
        when Array
          value.map { |v| jsonify(v) }
        else
          jsonify value.as_json
        end
      end

我可以做的是猴子补丁上述方法,接受我包装字符串的类,并什么都不做。

我想另一个选择是将JSON字符串解析回哈希表,并让它遵循正常程序。然而,那会影响我们的性能太大了。

因此,我的问题是,有没有更优雅的方法告诉Rails在尝试转换为JSON时遇到特定对象时什么都不做?

编辑:

我正在使用这个已经json化的字符串,例如:

{foo: MyStringJsonWrapper.new('{"bar":"foobar"}')}.to_json

你在控制器中如何调用它?记住当你使用 render json: @stuff 时,会调用 as_json 方法。你应该将这个方法命名为 as_json - Les Nightingill
嗨@LesNightingill,我这样调用它:{foo: MyStringJsonWrapper.new('{"bar":"foobar"}')}.to_json - DickieBoy
1个回答

2

我在文件activesupport-6.0.3.2/lib/active_support/json/encoding.rb中查看,并发现您可以配置用于执行json编码的类。当前使用的是该类中包含的JSONGemEncoder

因此,我创建了自己的类:

class MyJSONEncoder < ActiveSupport::JSON::Encoding::JSONGemEncoder
  class AlreadyEscapedString < String
    def to_json(*)
      self
    end
  end

  private

  def jsonify(value)
    if value.is_a?(AlreadyEncodedStringWrapper)
      AlreadyEscapedString.new(value.already_jsonified)
    else
      super
    end
  end
end

并且

class AlreadyEncodedStringWrapper
  attr_accessor :already_jsonified

  def initialize already_jsonified
    @already_jsonified = already_jsonified
  end

  def as_json(options = {})
    self
  end
end
AlreadyEscapedString这个额外的类存在的目的是为了覆盖EscapedString(在同一个编码类中找到)的行为,但是什么也不做。

然后只需设置:

ActiveSupport.json_encoder = MyJSONEncoder

例子:

jsonified_hash = {foobar: "barbaz"}.to_json

already_encoded_string = AlreadyEncodedStringWrapper.new(jsonified_hash)

{foo: already_encoded_string}.to_json
=> "{\"foo\": {\"foobar\": \"barbaz\"}}"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接