¿Cómo reemplazar a json en Rails?



Actualización:

Esta cuestión no fue explorada adecuadamente. El verdadero problema radica en render :json.

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

render :json => current_user

Es NO 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 User modelo, render :json => @user generará el ArgumentError descrito 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 render no está llamando a Model#to_json cuando se especifica type :json. ¿Alguien puede explicar lo que realmente está pasando aquí?

Cualquier genii que pueda ayudarme con esto probablemente pueda responder a mi otra pregunta: Cómo construir 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 no hago lo que estoy buscando.

Estoy tratando:

class User < ActiveRecord::Base

  # this actually works! (see update summary above)
  def to_json
    super(:only => :username, :methods => [:foo, :bar])
  end

end

Estoy recibiendo {[15] {} en[20]}

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

¿Alguna idea?

Author: Community, 2010-04-03

4 answers

Está obteniendo ArgumentError: wrong number of arguments (1 for 0) porque to_json necesita ser sobrescrito con un parámetro, el hash options.

def to_json(options)
  ...
end

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

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

Ahora, cada vez que to_json se llama a un objeto, as_json se invoca para crear los datos estructura, y luego ese hash se codifica como una cadena JSON usando ActiveSupport::json.encode. Esto sucede para todos los tipos: objeto, numérico, fecha, cadena, etc. (consulte el código de ActiveSupport).

Los objetos ActiveRecord se comportan de la misma manera. Hay una implementación predeterminada as_json que crea un hash que incluye todos los atributos del modelo. Debe reemplazar as_json en su Modelo para crear la estructura JSON que desea. as_json, al igual que el antiguo to_json, toma un hash de opción 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 es una cadena, se pasa a través como el cuerpo de respuesta, si es un objeto, se llama to_json, lo que desencadena as_json como se explicó anteriormente.

Por lo tanto, siempre y cuando sus modelos estén correctamente representados con as_json anula (o no), su código de controlador para mostrar un modelo debe tener este aspecto:

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

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

format.json { render :json => 
    @user.as_json(:only => [:username], :methods => [:avatar]) }
 206
Author: Jonathan Julian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-04 15:23:27

Si tiene problemas con esto en Rails 3, anule serializable_hash en lugar de as_json. Esto también te dará el formato XML gratis:)

Esto me llevó una eternidad averiguarlo. Espero que eso ayude a alguien.

 70
Author: Sam Soffes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-02 18:46:45

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

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:)

 30
Author: Danpe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-04 05:28:10

No sobrescriba to_json, sino as_json. Y de as_json llama a lo que quieras:

Prueba esto:

def as_json 
 { :username => username, :foo => foo, :bar => bar }
end
 3
Author: glebm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-03 19:25:16