3 votes

Arrêter l'encodage d'une chaîne dans un hash Ruby on Rails

J'essaie de ne pas jsonifier une chaîne dans un hash. Elle a déjà été échappée.

D'après ce que j'ai lu, la manière de gérer cela pour PORO est d'écraser as_json . J'ai donc enveloppé la chaîne dans un autre objet. Mais comme je n'ai affaire qu'à une chaîne de caractères qui mène à un objet de type stack level too deep lorsque je renvoie l'objet. Lorsque je renvoie la chaîne de caractères déjà encodée, elle essaie évidemment de l'échapper. 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

Ce que je pourrais faire, c'est de modifier la méthode ci-dessus pour accepter la classe dans laquelle j'ai enveloppé la chaîne et ne rien faire.

Je suppose que l'autre option consiste à analyser la chaîne JSON pour la transformer en hachage et à la laisser suivre la procédure normale. Mais cela aurait un impact trop important sur nos performances.

Ma question est donc la suivante : existe-t-il un moyen plus élégant de dire à Rails de ne rien faire lorsqu'il rencontre un objet spécifié et qu'il essaie de le jsonifier ?

Edita:

J'utilise cette chaîne déjà jsonifiée comme :

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

2voto

DickieBoy Points 1182

Je regardais dans le dossier activesupport-6.0.3.2/lib/active_support/json/encoding.rb et remarqué que vous pouvez configurer quelle classe est utilisée pour effectuer l'encodage json. C'est actuellement JSONGemEncoder qui est contenue dans cette classe.

Alors j'ai créé ma propre classe :

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

et

class AlreadyEncodedStringWrapper
  attr_accessor :already_jsonified

  def initialize already_jsonified
    @already_jsonified = already_jsonified
  end

  def as_json(options = {})
    self
  end
end

La classe supplémentaire de AlreadyEscapedString existe pour écraser le comportement de EscapedString (qui se trouvent dans la même classe d'encodage) mais ne font rien.

Ensuite, il suffit de mettre en place :

ActiveSupport.json_encoder = MyJSONEncoder

Ejemplo:

jsonified_hash = {foobar: "barbaz"}.to_json

already_encoded_string = AlreadyEncodedStringWrapper.new(jsonified_hash)

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X