Agregar atributo virtual a la salida json

Digamos que tengo una aplicación que maneja una lista TODO. La lista tiene elementos terminados y sin terminar. Ahora quiero agregar dos atributos virtuales al objeto de la lista; el recuento de elementos terminados y no finalizados en la lista. También necesito que estos se muestren en la salida json.

Tengo dos métodos en mi modelo que obtiene los elementos sin terminar / terminados:

def unfinished_items self.items.where("status = ?", false) end def finished_items self.items.where("status = ?", true) end 

Entonces, ¿cómo puedo obtener el recuento de estos dos métodos en mi salida json?

Estoy usando Rails 3.1

La serialización de objetos en Rails tiene dos pasos:

  • Primero, as_json es llamado para convertir el objeto a Hash simplificado.
  • Luego, to_json se to_json en el valor de retorno as_json para obtener la cadena JSON final.

Por lo general, quiere irse solo to_json , así que todo lo que necesita hacer es agregar su propia implementación as_json de la siguiente manera:

 def as_json(options = { }) # just in case someone says as_json(nil) and bypasses # our default... super((options || { }).merge({ :methods => [:finished_items, :unfinished_items] })) end 

También podrías hacerlo así:

 def as_json(options = { }) h = super(options) h[:finished] = finished_items h[:unfinished] = unfinished_items h end 

si desea utilizar diferentes nombres para los valores respaldados por método.

Si le importan XML y JSON, eche un vistazo a serializable_hash .

Con Rails 4, puede hacer lo siguiente:

 render json: @my_object.to_json(:methods => [:finished_items, :unfinished_items]) 

Espero que esto ayude a alguien que está en la última / última versión

Otra forma de hacerlo es agregar esto a su modelo:

 def attributes super.merge({'unfinished' => unfinished_items, 'finished' => finished_items}) end 

Esto también funcionaría automáticamente para la serialización xml. http://api.rubyonrails.org/classes/ActiveModel/Serialization.html Sin embargo, tenga en cuenta que es posible que desee utilizar cadenas para las claves, ya que el método no puede tratar con símbolos al ordenar las claves en Rails 3. Pero no es ordenados en Rails 4, por lo que ya no debería haber un problema.

simplemente cierre todos sus datos en un hash , como

render json: {items: items, finished: finished, unfinished: unfinished}

Solo pensé en proporcionar esta respuesta para cualquier persona como yo, que intentaba integrar esto en un bloque as_json existente:

  def as_json(options={}) super(:only => [:id, :longitude, :latitude], :include => { :users => {:only => [:id]} } ).merge({:premium => premium?}) 

Simplemente .merge({}) al final de tu super()

Como Aswin se mencionó anteriormente ,: los :methods le permitirán devolver el método / función de un modelo específico como un atributo json, en caso de que tenga assosiations complejas esto hará el truco ya que agregará funciones al modelo existente / assosiations: D funcionará como un amuleto si no quieres redefinir as_json

Verifique este código, y observe cómo estoy usando :methods , así como :include [N + Query ni siquiera es una opción;)]

render json: @YOUR_MODEL.to_json(:methods => [:method_1, :method_2], :include => [:company, :surveys, :customer => {:include => [:user]}])

Sobrescribir la función as_json será mucho más difícil en este escenario (especialmente porque tiene que agregar :include assosiations manualmente: / def as_json(options = { }) end

Esto servirá, sin tener que hacer algunas suposiciones desagradables. Si tiene una List modelo, por ejemplo, puede poner esto en su controlador:

  render json: list.attributes.merge({ finished_items: list.finished_items, unfinished_items: list.unfinished_items })