¿Cómo anular to_json en Rails?


Actualizar:

Este problema no fue explorado adecuadamente. El verdadero problema está en el render :json .

El primer código pegado en la pregunta original arrojará el resultado esperado. Sin embargo, todavía hay una advertencia. Mira este ejemplo:

render :json => current_user

NO es lo mismo que

render :json => current_user.to_json

Es decir, render :json no llamará automáticamente al método to_json asociado con el objeto User. De hecho , si to_json está siendo anulado en el modelo de User , render :json => @user generará el ArgumentError describe a continuación.

resumen

 # works if User#to_json is not overridden render :json => current_user # If User#to_json is overridden, User requires explicit call render :json => current_user.to_json 

Todo esto me parece tonto. Esto parece estar diciéndome que el render no llama realmente a Model#to_json cuando se especifica type :json . ¿Puede alguien explicar qué está pasando realmente aquí?

Cualquier genii que pueda ayudarme con esto probablemente pueda responder a mi otra pregunta: cómo crear una respuesta JSON combinando @ foo.to_json (opciones) y @ bars.to_json (opciones) en Rails.


Pregunta Original:

He visto algunos otros ejemplos en SO, pero ninguno hace lo que estoy buscando.

Lo estoy intentando:

 class User  :username, :methods => [:foo, :bar]) end end 

Obtengo ArgumentError: wrong number of arguments (1 for 0) en

 /usr/lib/ruby/gems/1.9.1/gems/activesupport-2.3.5/lib/active_support/json/encoders/object.rb:4:in `to_json 

¿Algunas ideas?

to_json ArgumentError: wrong number of arguments (1 for 0) porque to_json debe to_json con un parámetro, el hash de options .

 def to_json(options) ... end 

Explicación más larga de to_json , as_json y rendering:

En ActiveSupport 2.3.3, se agregó as_json para tratar problemas como el que ha encontrado. La creación del json debe estar separada de la representación del json.

Ahora, cuando to_json se to_json en un objeto, as_json se invoca para crear la estructura de datos, y luego ese hash se codifica como una cadena JSON usando ActiveSupport::json.encode . Esto ocurre para todos los tipos: objeto, numérico, fecha, cadena, etc. (ver el código de ActiveSupport).

Los objetos ActiveRecord se comportan de la misma manera. Hay una implementación as_json predeterminada que crea un hash que incluye todos los atributos del modelo. Debe anular as_json en su Modelo para crear la estructura JSON que desee . as_json , al igual que el antiguo to_json , toma un hash opcional donde puede especificar atributos y métodos para incluir declarativamente.

 def as_json(options) # this example ignores the user's options super(:only => [:email, :handle]) end 

En su controlador, render :json => o puede aceptar una cadena o un objeto. Si se trata de una cadena, se pasa como cuerpo de respuesta, si es un objeto, se llama to_json , que se activa as_json como se explicó anteriormente.

Por lo tanto, siempre y cuando sus modelos estén representados correctamente con as_json anulaciones (o no), su código de controlador para mostrar un modelo debería verse así:

 format.json { render :json => @user } 

La moraleja de la historia es: Evita llamar to_json directamente, permite que render haga eso por ti. Si necesita modificar la salida JSON, llame a as_json .

 format.json { render :json => @user.as_json(:only => [:username], :methods => [:avatar]) } 

Si tiene problemas con esto en Rails 3, anule serializable_hash lugar de as_json . Esto obtendrá su formato XML gratis también 🙂

Esto me tomó una eternidad para descubrirlo. Espero que ayude a alguien.

Para las personas que no quieren ignorar las opciones de los usuarios, sino también agregar las de ellos:

 def as_json(options) # this example DOES NOT ignore the user's options super({:only => [:email, :handle]}.merge(options)) end 

Espero que esto ayude a alguien 🙂

Anular no to_json, sino as_json. Y desde as_json llama a lo que quieras:

Prueba esto:

 def as_json { :username => username, :foo => foo, :bar => bar } end