2011-07-31 9 views
48

Digamos que tengo una aplicación que maneja una lista de cosas por hacer. 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 sin terminar en la lista. También necesito que estos se muestren en la salida json.Agregar atributo virtual a la salida de json

que tiene dos métodos en mi modelo que recoge los artículos sin terminar/acabados:

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

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

Así que, ¿cómo puedo obtener el recuento de estos dos métodos en mi salida JSON?

estoy usando Rails 3.1

+0

No he probado esto: tal vez lo único que tiene que hacer es agregar un attr_reader: finished_items? – mkro

Respuesta

95

La serialización de objetos en los carriles tiene dos pasos:

  • En primer lugar, se llama as_json para convertir el objeto a una Hash simplificado.
  • Luego, se llama al as_json valor de retorno para obtener la cadena JSON final.

Por lo general, quiere dejar to_json solos así que todo lo que necesita hacer es añadir your own as_json implementation algo así como esto:

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 puede hacerlo de esta manera:

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

si Querías usar diferentes nombres para los valores respaldados por método.

Si te preocupa XML y JSON, echa un vistazo a serializable_hash.

+3

Recibí este error con el superior: método indefinido 'merge 'for nil: NilClass Así que reemplacé' options.merge' con '(options || {}). Merge'. – Turadg

+0

@Turadg: El primero debería funcionar debido a 'options = {}' por defecto a menos que alguien esté pasando un 'nil' explícito en algún lugar, voy a parchar en la paranoia adicional solo para estar seguro. Lo siento, tu comentario se perdió en el caos diario, así que estoy un poco tarde para responderte. –

13

Otra manera de hacer esto es añadir esto a su modelo:

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

Esto también funcionaría de forma automática para la serialización XML. http://api.rubyonrails.org/classes/ActiveModel/Serialization.html Sin embargo, tenga en cuenta el uso de cadenas para las teclas, ya que el método no puede tratar con símbolos al clasificar las teclas en rieles 3. Pero no está ordenado en rieles 4, por lo que ya no debería haber ningún problema .

22

con los carriles 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 versión posterior/

+0

thx, este es un atajo realmente genial, especialmente para respuestas a javascript en combinación con OBD de BSON. – RunsnbunsN

0

simplemente pensé que proporcionar esta respuesta para alguien como yo , que estaba tratando de integrar este principio en un as_json bloque existente:

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

Sólo tachuela .merge({}) hasta el final de su super()

2

acaba de cerrar todos sus datos en uno de hash, como

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

0

Esto va a hacer, sin tener que hacer algunos overridings feas. Si tienes un modelo List por ejemplo, se puede poner esto en su controlador:

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

Como Aswin enumerados anteriormente, :methods le permitirá volver método/función de un modelo específico como un atributo JSON, en caso de tener assosiations complejas esto va a hacer el truco, ya que se sumará a las funciones de modelo/assossiations existentes: D que va a funcionar como un encanto si usted no quiere redefinir as_json

Comprobar el código, y por favor cuenta de lo que 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]}])

overwritting as_json función será mucho más difícil en este escenario (especialmente ya que hay que añadir los :include assossiations manualmente:/ def as_json(options = { }) end

Cuestiones relacionadas