Me pregunto ¿cuál es la mejor manera de convertir una con formato json valor de la clave par a ruby símbolo de hash con clave:
ejemplo:

{ 'user': { 'name': 'foo', 'age': 40, 'location': { 'city' : 'bar', 'state': 'ca' } } }
==> 
{ :user=>{ :name => 'foo', :age =>'40', :location=>{ :city => 'bar', :state=>'ca' } } }

Hay un método helper puede hacer esto?

  • pruebe este http://stackoverflow.com/a/43773159/1297435 para rails 4.1
InformationsquelleAutor ez. | 2009-11-13

7 Comentarios

  1. 247

    usando json joya al analizar la cadena json que puede pasar en el symbolize_names opción. Ver aquí: http://flori.github.com/json/doc/index.html (ver en la sección de análisis)

    por ejemplo:

    >> s ="{\"akey\":\"one\",\"bkey\":\"two\"}"
    >> JSON.parse(s,:symbolize_names => true)
    => {:akey=>"one", :bkey=>"two"} 
    • Ruby 1.9 incluye esta biblioteca, por el camino.
    • no solía ser :symbolize_keys ? ¿por qué ese cambio de nombre?
    • es un Rieles cosa.
    • Que es impresionante! Muchas gracias.
    • :symbolize_names es un Rubí cosa, aunque
  2. 19

    Leventix, gracias por tu respuesta.

    La Mariscal.de carga(Mariscal.vertedero(h)) método tiene probablemente la mayoría de la integridad de los diferentes métodos, ya que preserva la clave original de los tipos de de forma recursiva.

    Esto es importante en caso de tener un anidada hash con una combinación de cadena y teclas de símbolos y desea conservar que mezclar al decodificar (por ejemplo, esto puede ocurrir si el hash contiene sus propios objetos personalizados además de altamente complejo/anidada objetos de terceros cuyas teclas no se pueden manipular/convertir por la razón que sea, como un proyecto de limitación de tiempo).

    E. g.:

    h = {
          :youtube => {
                        :search   => 'daffy',                 # nested symbol key
                        'history' => ['goofy', 'mickey']      # nested string key
                      }
        }

    Método 1: JSON.parse – simboliza todas las claves de forma recursiva => no se conserva el original mix

    JSON.parse( h.to_json, {:symbolize_names => true} )
      => { :youtube => { :search=> "daffy", :history => ["goofy", "mickey"] } } 

    Método 2: ActiveSupport::JSON.decode – simboliza nivel superior solo las teclas => no se conserva el original mix

    ActiveSupport::JSON.decode( ActiveSupport::JSON.encode(h) ).symbolize_keys
      => { :youtube => { "search" => "daffy", "history" => ["goofy", "mickey"] } }

    Método 3: Mariscal.carga conserva cadena original/símbolo de la mezcla en el anidado de las teclas. PERFECTO!

    Marshal.load( Marshal.dump(h) )
      => { :youtube => { :search => "daffy", "history" => ["goofy", "mickey"] } }

    A menos que hay un inconveniente y es que no me he enterado, me gustaría pensar que el Método 3 es el camino a seguir.

    Saludos

    • No hay ninguna garantía de que usted tiene el control de el otro lado, así que creo que usted tiene que pegarse a formato JSON. Si usted tiene el control total de ambos lados, luego Mariscal de hecho es un buen formato, pero no es adecuado para el propósito general de la serialización.
  3. 5

    No hay nada construido en hacer el truco, pero no es demasiado difícil escribir el código para hacer que el uso de JSON joya. Hay un symbolize_keys método construido en Rails si usted está utilizando, pero que no simbolizan claves de forma recursiva como usted necesita.

    require 'json'
    
    def json_to_sym_hash(json)
      json.gsub!('\'', '"')
      parsed = JSON.parse(json)
      symbolize_keys(parsed)
    end
    
    def symbolize_keys(hash)
      hash.inject({}){|new_hash, key_value|
        key, value = key_value
        value = symbolize_keys(value) if value.is_a?(Hash)
        new_hash[key.to_sym] = value
        new_hash
      }
    end

    Como Leventix dijo, el JSON joya sólo se encarga de las cadenas entre comillas dobles (que es técnicamente correcta – JSON debe estar formateado con comillas dobles). Este trozo de código limpio que antes de intentar analizarlo.

  4. 4

    Método recursivo:

    require 'json'
    
    def JSON.parse(source, opts = {})
      r = JSON.parser.new(source, opts).parse
      r = keys_to_symbol(r) if opts[:symbolize_names]
      return r
    end
    
    def keys_to_symbol(h)
      new_hash = {}
      h.each do |k,v|
        if v.class == String || v.class == Fixnum || v.class == Float
          new_hash[k.to_sym] = v
        elsif v.class == Hash
          new_hash[k.to_sym] = keys_to_symbol(v)
        elsif v.class == Array
          new_hash[k.to_sym] = keys_to_symbol_array(v)
        else
          raise ArgumentError, "Type not supported: #{v.class}"
        end
      end
      return new_hash
    end
    
    def keys_to_symbol_array(array)
      new_array = []
      array.each do |i|
        if i.class == Hash
          new_array << keys_to_symbol(i)
        elsif i.class == Array
          new_array << keys_to_symbol_array(i)
        else
          new_array << i
        end
      end
      return new_array
    end
  5. 1

    Por supuesto, hay un json joya, pero que sólo se ocupa de las comillas dobles.

    • Como madlep dice a continuación – que es todo lo que usted necesita si usted sabe que el JSON será válido (por ejemplo, estás haciendo a ti mismo!)
    • Esto no funciona. JSON.parse(JSON.generate([:a])) # => ["a"]
    • Eso es porque JSON no puede representar símbolos. Usted puede utilizar: Marshal.load(Marshal.dump([:a])) lugar.
  6. 1

    Otra manera de manejar esto es el uso de YAML la serialización/deserialización, que también conserva el formato de la clave:

    YAML.load({test: {'test' => { ':test' => 5}}}.to_yaml) 
    => {:test=>{"test"=>{":test"=>5}}}

    Beneficio de este enfoque parece un formato que se adapta mejor para el RESTO de servicios…

    • Nunca vamos a obtener la entrada del usuario en YAML.carga: tenderlovemaking.com/2013/02/06/yaml-f7u12.html
    • ¿te refieres a este agujero de seguridad de 2013 aún no se soluciona el día de hoy?
    • Los símbolos son GC ed desde Ruby 2.2. YAML.load está destinado a serializar objetos arbitrarios (por ejemplo, para la memoria caché). La propuesta de YAML.safe_load se ha introducido un par de meses después de la entrada en el blog, así que es una cuestión de usar la cosa correcta: github.com/ruby/psych/commit/…
  7. 0

    La forma más conveniente es el uso de la nice_hash gema: https://github.com/MarioRuiz/nice_hash

    require 'nice_hash'
    my_str = "{ 'user': { 'name': 'foo', 'age': 40, 'location': { 'city' : 'bar', 'state': 'ca' } } }"
    
    # on my_hash will have the json as a hash
    my_hash = my_str.json
    
    # or you can filter and get what you want
    vals = my_str.json(:age, :city)
    
    # even you can access the keys like this:
    puts my_hash._user._location._city
    puts my_hash.user.location.city
    puts my_hash[:user][:location][:city]

Dejar respuesta

Please enter your comment!
Please enter your name here