3 Stimmen

Wie serialisiert man eingebettete Beziehungen in Ember Data?

Hintergrund

Tom Dale hat kürzlich angekündigt, dass "Embedded Loading jetzt zurück ist!" ist. Allerdings scheint es nur vollständig für das _laden_Szenario unterstützt zu werden. Es ist unklar, ob das serialisieren von eingebetteten Assoziationen noch in Entwicklung ist oder ob Benutzer erwartet werden, dies selbst umzusetzen, indem sie einen benutzerdefinierten Serializer erstellen.

Anforderungen

Das JSON für meine eingebettete Assoziation sieht so aus:

{
  inputs: [
    {
      id: 1,
      name: "Lieblingsfarbe",
      type: "SelectInput",
      options: {
        choices: [ 'rot', 'grün', 'gelb' ]
      }
    },   
    {
      id: 2,
      name: "E-Mail",
      type: "TextInput",
      options: {}
    }
  ]
}

Ich glaube, dass der "ember way" dies darzustellen ist, einen benutzerdefinierten Serializer zu erstellen, der mein JSON in Modelle wie diese umwandelt:

App.Choice = DS.Model.extend({
  name: DS.attr( 'string' ),
  input: DS.belongsTo( 'App.Input' )
});

App.Input = DS.Model.extend({
  name: DS.attr( 'string' ),
  type: DS.attr( 'string' ),
  choices: DS.hasMany( 'App.Choice' )
});

Versuchte Lösung

Die folgende Lösung funktioniert größtenteils, allerdings fühlt es sich so an, als ob ich etwas falsch mache, weil ich so viel Code umgekehrt ingenieurge und untergeordnet habe.

Customizer.MyRESTAdapter = DS.RESTAdapter.extend({
  dirtyRecordsForAttributeChange: function(dirtySet, record, attributeName, newValue, oldValue) {
    if(record.constructor === Customizer.Choice) {
      if(newValue === oldValue) { return; }

      var input = null;
      if (attributeName == 'name') {
        input = record.get('input');
      }
      else if(attributeName == 'input') {
        input = newValue;
      }
      if( input ) {
        dirtySet.add( input );
      }
    }
    else {
      this._super(dirtySet, record, attributeName, newValue, oldValue);
    }
  },

  dirtyRecordsForBelongsToChange: function(dirtySet, child, relationship) {
    if(child.constructor === Customizer.Choice) {
      var input = child.get( 'input' );
      if( input ) {
        dirtySet.add( input );
      }
    }
    else {
      this._super(dirtySet, child, relationship);
    }
  },

  dirtyRecordsForHasManyChange: function(dirtySet, parent, relationship) {
    this._super(dirtySet, parent, relationship);
  }
});

Customizer.MyRESTSerializer = DS.RESTSerializer.extend({
  init: function() {
    this._super();
    this.mappings.set( 'Customizer.Input', { choices: { embedded: 'load' } } );
  },

  extractEmbeddedHasMany: function(type, hash, key) {
    if(type == Customizer.Input) {
      if(!(hash['options'] && hash['options']['choices'])) { return null; }

      var choices = [];
      hash['options']['choices'].forEach(function(choice, i){
        var choiceId = hash['id'] + '_' + i;
        var inputId = hash['id'];
        choices[i] = { id: choiceId, input_id: inputId, name: choice };
      });
      return choices;
    }

    return this._super(type, hash, key);
  },

  addHasMany: function(data, record, key, relationship) {
    this._super(data, record, key, relationship);

    if( key === 'choices' ) {
      var choices = record.get('choices').map(function( choice ){
        return choice.get( 'name' );
      });
      data['options'] = data['options'] || {};
      data['options']['choices'] = choices;
    }
  }

});

Customizer.store = DS.Store.create({
  revision: 10,
  adapter: Customizer.MyRESTAdapter.create({
    namespace: 'api/v1',
    bulkCommit: false,
    serializer: Customizer.MyRESTSerializer
  })
})

Anfrage Für Feedback

  • Ist dies der richtige Weg?
  • Arbeitet das Ember-Team aktiv an einer besseren Lösung dafür?

1voto

Dan Gebhardt Punkte 3221

Schauen Sie sich den Branch embedded-records von ember-data an: https://github.com/emberjs/data/commits/embedded-records

Insbesondere sehen Sie sich diesen Commit zum Speichern von eingebetteten Daten an: https://github.com/emberjs/data/commit/0abd3b965c50dfeb23bd8ff50751825482050e68

Vollständige Unterstützung für eingebettete Datensätze steht direkt vor der Tür :)

Update

Der Branch embedded records wurde am 28.12.2012 in den master gemerged:

https://github.com/emberjs/data/commit/b5d7c478e79aa9706e0196b8769b7ef67bb26fc4

0voto

aceofspades Punkte 7510

Am Ende habe ich eine Variation von http://mozmonkey.com/2013/12/serializing-embedded-relationships-ember-data-beta/ verwendet. In meinem Fall füge ich die id zum JSON hinzu oder wenn es nicht geändert wurde, sende ich einfach die id alleine.

class App.ApplicationSerializer extends DS.ActiveModelSerializer
  # Basierend auf http://mozmonkey.com/2013/12/serializing-embedded-relationships-ember-data-beta/
  # Siehe auch http://discuss.emberjs.com/t/ember-data-beta-3-and-saving-hasmany-relationships-with-activemodelserializer`-and-rails/3167
  serializeHasMany: (record, json, relationship) ->
    key = relationship.key
    hasManyRecords = Ember.get(record, key)
    embed = relationship.options.embed
    if embed && hasManyRecords
      json[key] = []
      hasManyRecords.forEach (item, index) =>
        json[key].push @serializeItem(item, embed)
    else
      @._super(record, json, relationship)

  serializeBelongsTo: (record, json, relationship) ->
    key = relationship.key
    belongsToRecord = Ember.get(record, key)
    embed = relationship.options.embed
    if embed
      json[key] = @serializeItem(belongsToRecord, embed)
    else
      @._super(record, json, relationship)

  serializeItem: (item, embed) ->
    if embed == 'ifDirty'
      if item.isDirty
        data = item.serialize()
      else
        data = {}
      data['id'] = item.id
    else if embed == 'always'
      data = item.serialize()
      data['id'] = item.id
    else
      null
    data

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X