Doing embedded serialization in ember-data 1.0.0-beta-8


#1

I have a fairly complicated model with a lot of hasMany and belongsTo relationships. When I save the parent model, instead of just the IDs, I want to save the contents of all nested objects as well.

Since this isn’t supported by default I thought I’d override serializeHasMany and belongsTo on the adapter. But it turns out my record object is a promise and invoking “then” to resolve it causes the object to be serialized without that property.

I suspect calling “then” sticks it on a queue of stuff to do. The end result is that the final JSOn doesn’t include promise fields.

I went further and got it almost working, but for some reason I’m missing fields in some cases, like “id”. Although the other properties of the nested object gets resolved and included in the final JSON.

Code I have so far is:


Impulse.ApplicationAdapter = DS.RESTAdapter.extend({
//    namespace: 'api/1',
//    host:''
    updateRecord: function (store, type, record) {
        record.set('_asyncResolving', Ember.ArrayProxy.create({content: []}));
        var data = {};
        var serializer = store.serializerFor(type.typeKey);
        serializer.serializeIntoHash(data, type, record);
        var id = record.get('id');
        console.log('quote data', data);
//        return this.ajax(this.buildURL(type.typeKey, id), "PUT", { data: data });
        var $this = this;

        function doSend(resolve, reject) {
            $this.ajax($this.buildURL(type.typeKey, id), "PUT", { data: data }).then(function () {
                    resolve.apply($this, arguments)
                },
                function () {
                    reject.apply($this, arguments)
                })
        }

        return new Ember.RSVP.Promise(function (resolve, reject) {
            var outstanding = record.get('_asyncResolving'), expecting = outstanding.get('length'), success = 0, failure = 0;

            outstanding.forEach(function (p) {
                p.then(function () {
                    ++success;
                    console.log(success, failure, expecting);
                    if (success + failure + 1 == expecting) {
                        doSend(resolve, reject)
                    }
                }, function () {
                    ++failure;
                    console.log(success, failure, expecting);
                    if (success + failure + 1 == expecting) {
                        doSend(resolve, reject)
                    }
                })
            })
        });
    }
});
DS.RESTSerializer.reopen({
    //http://mozmonkey.com/2013/12/serializing-embedded-relationships-ember-data-beta/
    serializeHasMany: function (record, json, relationship) {
        var key = relationship.key,
            hasManyRecord = record.get(key);

        // Embed hasMany relationship if records exist
        if (hasManyRecord && relationship.options.fat === true) {
            record.get('_asyncResolving').addObject(new Ember.RSVP.Promise(function (resolve, reject) {
                hasManyRecord.then(function (r) {
                    json[key] = [];
                    r.forEach(function (item, index) {
                        json[key].push(item.toJSON());
                    });
                    resolve(json)
                })
            }));
        }
        // Fallback to default serialization behavior
        else {
            return this._super(record, json, relationship);
        }
    },
    serializeBelongsTo: function (record, json, relationship) {
        var key = relationship.key,
            belongsTo = record.get(key);
        if (belongsTo && relationship.options.fat === true) {
            record.get('_asyncResolving').addObject(new Ember.RSVP.Promise(function (resolve, reject) {
                belongsTo.then(function (value) {
                    json[key] = value.toJSON();
                    resolve(json);
                });
            }));
        }
        else {
            return this._super(record, json, relationship);
        }
    }
});

Is there another way to do this or any idea why I’m missing the id field? I really don’t want to make N PUT requests to save what can be a single request.


#2

You had a look at this? Sound like what you want to me. http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html


#3

:frowning: I totally missed that! It does look like what I want. Thanks for the link I’ll give that a go and see but it does look like it is exactly what I want.


#4

If you need help, give a shout. We are using it as well and if you have other serializer customizations it can fall on your foot (dont know if that saying is understandable in english :wink: ).


#5

Thanks, I had a go at that. After spending some time looking at how it is implemented and what I’d need to change it’d actually be more work to refactor everything else already being side loaded (both client and server side). It also feels like it’ll be a continuously uphill battle with ember data if everything isn’t side loaded.

So I’m not doing embedded records anymore. Written what I needed to sort that and all is proceeding


#6

Well, it worked for me. But you are right. At the moment its easier to embed belongsTo records. But I still have hope it gets better the closer we get to a release candidate for Ember data.