underscore template backbonejs json inheritance backbone.js coffeescript

json - template - backbonejs github



Una colección de Backbone.js de múltiples subclases de modelos (5)

Tengo una API REST Json que devuelve una lista de "libros de registro". Existen muchos tipos de registros que implementan comportamientos diferentes pero similares. La implementación del lado del servidor en la capa Base de datos es una especie de herencia de tabla única, por lo que cada representación JSON de un libro de registro contiene su "tipo":

[ {"type": "ULM", "name": "My uml logbook", ... , specific_uml_logbook_attr: ...}, {"type": "Plane", "name": "My plane logbook", ... , specific_plane_logbook_attr: ...} ]

Me gustaría replicar este modelo de servidor en el lado del cliente, así que tengo una clase básica de Logbook y múltiples subclases de logbook:

class Logbook extends Backbone.Model class UmlLogbook extends Logbook class PlaneLogbook extends Logbook ...

My Backbone.Collection es un conjunto de modelos de Logbook que uso para consultar la API de JSON:

class LogbookCollection extends Backbone.Collection model: Logbook url: "/api/logbooks"

Cuando busco la colección del libro de registro, ¿hay alguna manera de convertir cada libro de registro a su subclase correspondiente (según el atributo "tipo" de JSON)?


De hecho hay

Cuando llamas ''fetch'' a una colección, pasa la respuesta a través de Backbone.Collection.parse antes de agregarlo a la colección.

La implementación predeterminada de ''parse'' solo pasa la respuesta como está, pero puede anularla para devolver una lista de modelos que se agregarán a la colección:

class Logbooks extends Backbone.Collection model: Logbook url: ''api/logbooks'' parse: (resp, xhr) -> _(resp).map (attrs) -> switch attrs.type when ''UML'' then new UmlLogbook attrs when ''Plane'' then new PLaneLogbook attrs

EDITAR: whoa, idbentley llegó antes que yo. la única diferencia es que usó ''cada'' y yo usé ''mapa''. Ambos funcionarán, pero de manera diferente.

El uso de ''cada'' rompe efectivamente la cadena que inició la llamada ''búsqueda'' (al devolver ''indefinido'' - la subsecuente llamada a ''reiniciar'' (o ''agregar'') por lo tanto no hará nada) y hace todo el procesamiento allí en el análisis función.

El uso de ''mapa'' simplemente transforma la lista de atributos en una lista de modelos y la pasa nuevamente a la cadena que ya está en movimiento.

Diferentes golpes.

EDITAR DE NUEVO: acaba de darse cuenta de que también hay otra forma de hacer esto:

El atributo ''modelo'' en una colección está allí solo para que la colección sepa cómo crear un nuevo modelo si se le pasan atributos en ''agregar'', ''crear'' o ''restablecer''. Entonces podrías hacer algo como:

class Logbooks extends Backbone.Collection model: (attrs, options) -> switch attrs.type when ''UML'' then new UmlLogbook attrs, options when ''Plane'' then new PLaneLogbook attrs, options # should probably add an ''else'' here so there''s a default if, # say, no attrs are provided to a Logbooks.create call url: ''api/logbooks''

La ventaja de esto es que la colección ahora sabrá cómo "lanzar" la subclase correcta de Logbook para operaciones que no sean ''fetch''.


Sí. Puede anular la función de parse en la colección (voy a utilizar javascript en lugar de coffeescript, porque es lo que sé, pero la asignación debe ser fácil):

LogbookCollection = Backbone.Collection.extend({ model: Logbook, url: "/api/logbooks", parse: function(response){ var self = this; _.each(response, function(logbook){ switch(logbook.type){ case "ULM": self.add(new UmlLogBook(logbook); break; case "Plane": ... } } } });

Espero que esto ayude.


Tal vez es malo usar eval, pero esto es mucho más estilo ruby ​​way (coffeescript):

parse: (resp)-> _(resp).map (attrs) -> eval("new App.Models.#{attrs.type}(attrs)")

Por lo tanto, no necesita escribir muchos conmutadores / mayúsculas, simplemente configure el atributo de tipo en su JSON. Funciona muy bien con rails + citier u otra solución de herencia multitable. Puede agregar nuevos descendientes sin agregarlos a sus casos.

Y puede usar tales construcciones en otros lugares donde necesite muchos conmutadores / cajas dependiendo de su clase de modelo.


a partir de la red troncal 0.9.1, comencé a usar el método descrito en la solicitud de extracción de esa-matti suuronen:

https://github.com/documentcloud/backbone/pull/1148

después de aplicar el parche, su colección sería algo como esto:

LogbookCollection = Backbone.Collection.extend({ model: Logbook, createModel: function (attrs, options) { if (attrs.type === "UML") { // i''am assuming ULM was a typo return new UmlLogbook(attrs, options); } else if (attrs.type === "Plane") { return new Plane(attrs, options); } else { return new Logbook(attrs, options); // or throw an error on an unrecognized type // throw new Error("Bad type: " + attrs.type); } } });

creo que esto cabría ya que estás usando STI (todos los modelos tienen identificadores únicos)