2013-02-28 3 views
9

Sto avendo difficoltà a salvare una relazione uno-a-molti nei dati di bordo. Ho un rapporto come questo:Dati di braci che salvano una relazione

App.ParameterSet = DS.Model 
    name: DS.attr("string") 
    regions: DS.hasMany("App.Region") 

App.Region = DS.Model 
    name: DS.attr("string") 

Se dovessi fare qualcosa di simile:

parameterSet = App.ParameterSet.find(5) 
@transaction = @get("store").transaction() 
@transaction.add(parameterSet) 
region1 = App.Region.find(10) 
region2 = App.Region.find(11) 
parameterSet.set("name", "foo") 
parameterSet.get("regions").pushObject(region) 
@transaction.commit() 

Poi mi piacerebbe vedere una richiesta PUT con carico utile in questo modo:

api/ParameterSets/5 

{parameterSet: {name: "foo", regionIds:[10, 11]}} 

ma invece ottengo questo:

{parameterSet: {name: "foo"}} 

Non mi interessa la relazione da bambino a genitore ma se aggiungo parameterSet: DS.belongsTo("App.ParameterSet") al modello App.Region poi ottengo 2 richieste PUT all'URL delle regioni per le due nuove relazioni che non è proprio quello che voglio.

Immagino che questa sia una relazione molti-a-molti che non sono ancora supportata, ma qualche idea su come ottenere ciò che ho descritto? Grazie

risposta

8

La serializzazione delle relazioni hasMany viene gestita dal metodo addHasMany() di json_serializer.js.

La seguente nota è inclusa nel source code:

semantica REST

Il default sono di aggiungere solo un rapporto ha-molti se è incorporato. Se la relazione è stata inizialmente caricata dall'ID, si presuppone che sia stato eseguito come ottimizzazione delle prestazioni e che le modifiche allo debbano essere salvate come modifiche della chiave esterna sulla relazione appartenente al figlio.

Per ottenere ciò che si desidera, un'opzione è indicare che la relazione deve essere incorporata nell'adattatore.

App.Store = DS.Store.extend({ 
    adapter: DS.RESTAdapter.extend({ 
    serializer: DS.RESTSerializer.extend({ 
     init: function() { 
     this._super(); 
     this.map('App.ParameterSet', { 
      regions: { embedded: 'always' } 
     }); 
     } 
    }) 
    }) 
}); 

Naturalmente adesso la tua back-end sarà necessario incorporare in realtà JSON le regioni associate all'interno JSON il parametro del set. Se vuoi mantenere le cose come sono, puoi semplicemente sostituire lo addHasMany() con la serializzazione personalizzata.

App.Store = DS.Store.extend({ 
    adapter: DS.RESTAdapter.extend({ 
    serializer: DS.RESTSerializer.extend({ 
     addHasMany: function(hash, record, key, relationship) { 
     // custom ... 
     } 
    }) 
    }) 
}); 
+0

Grande, grazie che aiuta molto – Charlie

+0

Questo è molto utile, grazie! Penso che sia un'ipotesi miope per far sì che i dati ember! – KOGI

+0

Qual è il motivo di questa "ottimizzazione"? Posso vedere che si tratta di un'ottimizzazione durante il caricamento, ma come aiuta durante il salvataggio? Se volessi aggiungere 100 oggetti figlio a un oggetto padre, in questo modo, dovrei aggiungere l'ID genitore a ogni bambino e salvare ogni bambino individualmente (100 richieste POST/PUT separate), mentre, I * potrebbe * avere solo ha aggiunto tutti i 100 ID al genitore e fatto un singolo POST/PUT ed è stato fatto. – KOGI

2

Io non sono in grado di aggiungere commenti alla risposta di ahmacleod, ma è a posto, tranne che ho notato che il record principale non viene contrassegnato come sporco quando il record del bambino viene modificato. Nell'esempio della domanda, il problema non si pone perché il nome viene modificato anche sul record padre.

In generale, tuttavia, se si seguirà la seconda risposta di ahmacleod, è necessario eseguire l'override del metodo dirtyRecordsForHasManyChange su RESTAdapter. Altrimenti, addHasMany nel serializzatore non viene mai chiamato, poiché il record non è nemmeno segnato come sporco.

il metodo esistente assomiglia:

dirtyRecordsForHasManyChange: function(dirtySet, record, relationship) { 
    var embeddedType = get(this, 'serializer').embeddedType(record.constructor, relationship.secondRecordName); 

    if (embeddedType === 'always') { 
    relationship.childReference.parent = relationship.parentReference; 
    this._dirtyTree(dirtySet, record); 
    } 
}, 

quindi credo che si vorrà qualcosa di simile:

App.Store = DS.Store.extend({ 
    adapter: DS.RESTAdapter.extend({ 
    dirtyRecordsForHasManyChange: function(dirtySet, record, relationship) { 
     relationship.childReference.parent = relationship.parentReference; 
     this._dirtyTree(dirtySet, record); 
    }, 

    serializer: DS.RESTSerializer.extend({ 
     addHasMany: function(hash, record, key, relationship) { 
     // custom ... 
     } 
    }) 
    }) 
}); 
+0

Non l'ho ancora provato, ma sembra una buona presa. – ahmacleod