2009-03-25 15 views
12

Estoy perplejo con este problema.¿Cómo lidiar con el conflicto entre ActiveSupport :: JSON y la joya JSON?

ActiveSupport::JSON define to_json en varios objetos centrales, al igual que la gema JSON. Sin embargo, la implementación no es la misma: la versión de ActiveSupport toma argumentos y la versión de joya JSON no.

Instalé una gema que requería la gema JSON y mi aplicación se rompió. El problema es que estoy usando to_json en un controlador que devuelve una lista de objetos, pero quiero controlar qué atributos se devuelven.

Cuando el código en cualquier parte de mi sistema hace require 'json' me sale este mensaje de error:

TypeError: wrong argument type Hash (expected Data)

he intentado un par de cosas que he leído en línea para solucionarlo, pero nada funcionó. Terminé reescribiendo la gema para usar ActiveSupport::JSON.decode en lugar de JSON.parse.

Esto funciona pero no es sostenible ... No puedo bifurcar gemas cada vez que quiero usar una gema que requiere la gema JSON.

Actualización: La mejor solución a este problema es actualizar a Rails 2.3 o superior, que lo corrigió.

+1

¿Por qué esta pregunta marcado como "comunidad wiki"? –

+0

No lo sé, pensé que probaría eso y vería qué hace. –

+0

He sentido tu dolor, espero que este lío sea resuelto algún día – MatthewFord

Respuesta

2

ActualizaciónEsta revisión solo es aplicable a Rails < 2.3. Como Giles menciona a continuación, arreglaron esto en 2.3 internamente usando casi la misma técnica. Pero ten cuidado con el anterior intento de la gema json en la compatibilidad con Rails (json/add/rails), que, si es necesario, romperá todo de nuevo.

¿Se refiere a la declaración require 'json' en sí misma que plantea que Exception? ¿O quiere decir que cuando llama al @something.to_json(:something => value), obtiene el error? Lo último es lo que esperaría, si tienes un problema que requiera la joya JSON, entonces no estoy seguro de lo que está pasando.

Acabo de toparme con este problema con la gema oauth. En mi caso, no hay un verdadero conflicto, porque la oauth gem no depende de la implementación to_json. Por lo tanto, el problema es que JSON está criticando las declaraciones de ActiveSupport. Lo resolví simplemente requiriendo json antes de que se cargue ActiveSupport. Poner

require 'json' 

dentro del Rails::Initializer resolvieron el problema (aunque ponerlo después del bloque no).

Eso permite que ActiveSupport limpie la implementación JSON predeterminada en su lugar.

Ahora, si está utilizando una joya que realmente depende de la implementación JSON de to_json, entonces está en un riachuelo. Esto es definitivamente lo peor de la meta-programación, y recomendaría que los desarrolladores de gemas Rails y JSON resuelvan el conflicto, aunque será doloroso porque uno u otro tendrán que romper la compatibilidad hacia atrás.

En el corto plazo, los autores de gemas pueden salvar la brecha apoyando ambas implementaciones. Esto es más o menos factible dependiendo de cómo la gema usa el método. El peor de los casos es un tenedor oficial (es decir, gem y gem-rails).

+0

Sí, quiero decir que cuando uso algo que requiere llamadas 'json', destruye la versión de Rails de to_json y me causa mucho dolor. Gracias por sus sugerencias. ¿Has tenido algo de suerte con la opción sugerida de usar require 'json/add/rails'? No puedo hacer que eso funcione. –

+0

requiere que solo funcione la primera vez que lo llame, de modo que si lo llama antes de que se cargue la versión de Rails, no hará nada cuando el complemento lo requiera. Lo verifiqué en la práctica, lo puse en el bloque Rails :: Initializer. No tengo idea de lo de json/add/rails, pero no creo que sea necesario. – gtd

0

Estoy bastante seguro de que arreglaron esto en 2.3, pero no recuerdo cómo.

+0

Sí, creo que se deshicieron de llamar a_json directamente. En su lugar, define as_json o llama directamente a JSON.generate o ActiveSupport :: JSON.encode. Y con las nuevas cosas de back-end JSON, creo que ActiveSupport :: JSON.encode usará su biblioteca preferida. –

0

todavía tengo que probarlo, pero parece Rails 2.3.3 le da cierto control:

ActiveSupport::JSON.backend = 'JSONGem' 

Found here

+0

Sí, Rails 2.3+ soluciona este problema. –

0

En mi caso aunque único, que tenía un rubí (no rails) aplicación que en realidad cargó una aplicación de Rails (desde una carga de config/environment.rb) así como algunas gemas que hicieron referencia a json. Esto me causó grandes dolores de cabeza debido al hecho de que no podía simplemente alterar el archivo environment.rb de la aplicación Rails. Terminé bifurcando un número de gemas para que json funcione sin generar el temido mensaje TypeError: argumento erróneo tipo Hash (datos esperados).

tuve un poco de suerte con esta solución, que es exactamente lo contrario ya que la respuesta de la comunidad wiki arriba ... http://blog.swivel.com/code/2009/03/active-support-and-json-gems-dont-play-nice.html que básicamente aboga llamando requieren 'active_support' ANTES requieren 'json'

Esta fue la única forma en que pude hacerlo funcionar, y créanme, lo intenté todo durante muchos meses.

18

ACTUALIZACIÓN: incluso con Rails 3.2, el mismo problema permanece sin corregir. El desagradable truco para cargar a la fuerza la gema json y sobreescribirla, eso es.

Eventualmente terminé con el siguiente código, para eludir por completo el to_json de ActiveSupport por completo. Póngalo en config/initializers/patches.rb, y puede hacer {}.jsonize o [].jsonize para generar cadena JSON. No hay conflictos con nada, garantizado.

# Undo the effect of 'active_support/core_ext/object/to_json' 
require 'json' 
[Object, Array, Hash].each do |klass| 
    klass.class_eval <<-RUBY, __FILE__, __LINE__ 
    def jsonize(options = nil) 
     ::JSON.generate self, :quirks_mode => true 
    end 
    RUBY 
end 

Las 8 líneas de código que tu aplicación 50 veces más rápido para JSON codificación. Probablemente quieras hacer lo mismo. :)


He estado teniendo un problema similar hasta Rails 2.3.8.

El problema es que ActiveSupport::JSON.backend = 'JSONGem' es una solución a medias y aún necesita sobrescribir algunos codificadores usted mismo. (ADVERTENCIA:. Rieles para 3.x, que utiliza MultiJson, debe ser al menos ActiveSupport::JSON.backend = :json_gem, o será en silencio no-op)

En mi caso, necesitaba para sobrescribir String#to_json porque JSON joya 1.4. 3 es mejor porque no codifica ciegamente caracteres UTIF8 no ascii-pero-válidos en la forma de "\uXXXX" donde no es necesario, por lo que se obtienen bytes más cortos (buenos para la serialización) y resultados fáciles de leer ("日本語" se ve mucho más sexy para mis ojos que "\u65e5\u672c\u8a9e").

Aquí está el parche mono que he estado usando - poner el siguiente código en config/initializers/patches.rb

module ActiveSupport 
    module JSON 
    module Encoding 
     class << self 
     def escape(string) 
      ::JSON.generate([string])[1..-2] 
     end 
     end 
    end 
    end 
end 

y usted es libre de utilizar en cualquier cosa to_json - cadena, matriz y Hash.

+0

Esto funcionó con la fijación de Emoji en Rails 3.1.3. Gracias. – Chalkers

3

Después de luchar contra esto durante un tiempo .. He encontrado la solución más simple para ser:

if defined?(ActiveSupport::JSON) 
    [Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass].each do |klass| 
    klass.class_eval do 
    def to_json(*args) 
     super(args) 
    end 
    def as_json(*args) 
     super(args) 
    end 
    end 
    end 
end 

puesto que en cualquier lugar después ActiveSupport se carga ..

Cuestiones relacionadas