Данные Ember принадлежат к асинхронным отношениям, исключенным из сериализации createRecord() save()

Редактировать 16.11.14: Информация о версии

DEBUG: Ember      : 1.7.0 ember-1.7.0.js:14463
DEBUG: Ember Data : 1.0.0-beta.10+canary.30d6bf849b ember-1.7.0.js:14463
DEBUG: Handlebars : 1.1.2 ember-1.7.0.js:14463
DEBUG: jQuery     : 1.10.2 

Я бьюсь головой о стену, пытаясь сделать что-то, что, на мой взгляд, должно быть довольно простым с данными о тлеющих углях и угасающих угрях, но мне пока не повезло.

По сути, я хочу использовать данные сервера для заполнения <select> выпадающее меню. Когда форма отправлена, модель должна быть создана на основе данных, выбранных пользователем. Затем модель сохраняется с данными ember и пересылается на сервер в следующем формате:

{ 
    "File": { 
        "fileName":"the_name.txt",
        "filePath":"/the/path",
        "typeId": 13,
        "versionId": 2
    }
}

Проблема в том, что typeId и versionId не учитываются, когда отношение модели определяется как асинхронное, например:

App.File =  DS.Model.extend({
    type: DS.belongsTo('type', {async: true}),
    version: DS.belongsTo('version', {async: true}),
    fileName: DS.attr('string'),
    filePath: DS.attr('string')
});

Часть, которая сбивает меня с толку, и, вероятно, где мои ошибки лежат, это контроллер:

App.FilesNewController = Ember.ObjectController.extend({
    needs: ['files'],
    uploadError: false,

    // These properties will be given by the binding in the view to the 
    //<select> inputs.  
    selectedType: null,
    selectedVersion: null,

    files: Ember.computed.alias('controllers.files'),

    actions: {
        createFile: function() {
            this.createFileHelper();
        }
    },

    createFileHelper: function() {
        var selectedType = this.get('selectedType');
        var selectedVersion = this.get('selectedVersion');

        var file = this.store.createRecord('file', {
                fileName: 'the_name.txt',
                filePath: '/the/path'
        });

        var gotDependencies = function(values) {

            //////////////////////////////////////
            // This only works when async: false
            file.set('type', values[0])
                .set('version', values[1]);
            //////////////////////////////////////

            var onSuccess = function() {
                this.transitionToRoute('files');
            }.bind(this);

            var onFail = function() {
                this.set('uploadError', true);
            }.bind(this);

            file.save().then(onSuccess, onFail);
        }.bind(this);

        Ember.RSVP.all([
            selectedType,
            selectedVersion
        ]).then(gotDependencies);
    }
});

Когда для async установлено значение false, угасающие ручки createRecord().save() POST запрашивает правильно.

Когда async имеет значение true, ember прекрасно обрабатывает GET-запросы с несколькими запросами, но НЕ добавляет отношения ownTo к файлу JSON во время createRecord().save(), Только основные свойства сериализуются:

{"File":{"fileName":"the_name.txt","filePath":"/the/path"}}

Я понимаю, что этот вопрос уже задавался, но пока не нашел удовлетворительного ответа и не нашел ничего, что отвечало бы моим потребностям. Итак, как я могу получить правильную сериализацию отношения отношение к?

Просто чтобы быть уверенным, что все здесь, я добавлю пользовательскую сериализацию, которую я имею до сих пор:

App.ApplicationSerializer = DS.RESTSerializer.extend({
    serializeIntoHash: function(data, type, record, options) {
        var root = Ember.String.capitalize(type.typeKey);
        data[root] = this.serialize(record, options);
    },
    keyForRelationship: function(key, type){
        if (type === 'belongsTo') {
            key += "Id";
        }
        if (type === 'hasMany') {
            key += "Ids";
        }
        return key;
    }
});

App.FileSerializer = App.ApplicationSerializer.extend(DS.EmbeddedRecordsMixin, {
    attrs: {
        type: { serialize: 'id' },
        version: { serialize: 'id' }
    }
});

И выберите:

{{ view Ember.Select
    contentBinding="controller.files.versions"
    optionValuePath="content"
    optionLabelPath="content.versionStr"
    valueBinding="controller.selectedVersion"
    id="selectVersion"
    classNames="form-control"
    prompt="-- Select Version --"}}

При необходимости я добавлю другие маршруты и контроллеры (FilesRoute, FilesController, VersionsRoute, TypesRoute)

РЕДАКТИРОВАТЬ 16/16/14

У меня есть рабочее решение (хак?), Которое я нашел на основе информации в двух соответствующих темах:

1) Как асинхронные отношения должны быть сериализованы?

2) Поддерживает ли async соответствующее назначение модели?

По сути, все, что мне нужно было сделать, это переместить Ember.RSVP.all() после get() по свойствам:

createFileHelper: function() {
    var selectedType = this.get('selectedType');
    var selectedVersion = this.get('selectedVersion');

    var file = this.store.createRecord('file', {
            fileName: 'the_name.txt',
            filePath: '/the/path',
            type: null,
            version: null
    });


    file.set('type', values[0])
        .set('version', values[1]);

    Ember.RSVP.all([
        file.get('type'),
        file.get('version')
    ]).then(function(values) {

        var onSuccess = function() {
            this.transitionToRoute('files');
        }.bind(this);

        var onFail = function() {
            alert("failure");
            this.set('uploadError', true);
        }.bind(this);

        file.save().then(onSuccess, onFail);
    }.bind(this));
}

Так что мне нужно было get() свойства, которые принадлежали отношениям, прежде чем я сохраню модель. Я не знаю, является ли это ошибкой или нет. Может быть, кто-то с большим знанием о emberjs может помочь пролить свет на это.

1 ответ

Решение

См. Вопрос для получения более подробной информации, но общий ответ, который я работал для меня при сохранении модели с отношением ownTo (и вам необходимо, чтобы это отношение было сериализовано), заключается в вызове .get() на свойствах, а затем save() их в then(),

Это сводится к этому:

var file = this.store.createRecord('file', {
        fileName: 'the_name.txt',
        filePath: '/the/path',
        type: null,
        version: null
});

// belongsTo set() here
file.set('type', selectedType)
    .set('version', selectedVersion);

Ember.RSVP.all([
    file.get('type'),
    file.get('version')
]).then(function(values) {

    var onSuccess = function() {
        this.transitionToRoute('files');
    }.bind(this);

    var onFail = function() {
        alert("failure");
        this.set('uploadError', true);
    }.bind(this);

    // Save inside then() after I call get() on promises
    file.save().then(onSuccess, onFail);

}.bind(this));
Другие вопросы по тегам