简体   繁体   English

Ember Data属于从createRecord()save()序列化中省略的异步关系

[英]Ember Data belongsTo async relationship omitted from createRecord() save() serialization

Edit 11/16/14: Version Information 编辑2014年11月16日:版本信息

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 

I'm beating my head against a wall trying to do something that I think should be fairly straightforward with ember and ember-data, but I haven't had any luck so far. 我正试图做一些我认为应该用ember和ember-data 相当简单的事情,但我到目前为止还没有任何运气。

Essentially, I want to use server data to populate a <select> dropdown menu. 基本上,我想使用服务器数据来填充<select>下拉菜单。 When the form is submitted, a model should be created based on the data the user chooses to select. 提交表单时,应根据用户选择的数据创建模型。 The model is then saved with ember data and forwarded to the server with the following format: 然后使用ember数据保存模型,并使用以下格式转发到服务器:

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

The problem is, the typeId and versionId are left out when the model relationship is defined as async like so: 问题是,当模型关系被定义为异步时,类型Id和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')
});

The part that is confusing me, and probably where my mistakes lie, is the controller: 让我感到困惑的部分,可能是我的错误所在,是控制器:

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);
    }
});

When async is set to false, ember handles createRecord().save() POST requests correctly. 当async设置为false时,ember会正确处理createRecord().save() POST请求。

When async is true, ember handles GET requests perfectly with multiple requests, but does NOT add the belongsTo relationships to the file JSON during createRecord().save() . 当async为true时,ember会在多个请求中完美地处理GET请求,但在createRecord().save()期间不会将belongsTo关系添加到文件JSON。 Only the basic properties are serialized: 只序列化基本属性:

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

I realize this question has been asked before but I have not found a satisfactory answer thus far and I have not found anything that suits my needs. 我之前已经意识到这个问题,但到目前为止我还没有找到满意的答案,而且我找不到任何适合我需要的答案。 So, how do I get the belongsTo relationship to serialize properly? 那么,如何让belongsTo关系正确序列化?

Just to be sure that everything is here, I will add the custom serialization I have so far: 为了确保一切都在这里,我将添加到目前为止的自定义序列化:

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' }
    }
});

And a select: 并选择:

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

If necessary I will append the other routes and controllers (FilesRoute, FilesController, VersionsRoute, TypesRoute) 如果有必要,我会追加其他路由和控制器(FilesRoute,FilesController,VersionsRoute,TypesRoute)

EDIT 11/16/14 编辑 11/16/14

I have a working solution (hack?) that I found based on information in two relevant threads: 我有一个工作解决方案(黑客?),我根据两个相关主题中的信息找到了:

1) How should async belongsTo relationships be serialized? 1) async属性应该如何序列化?

2) Does async belongsTo support related model assignment? 2) async属于支持相关的模型分配吗?

Essentially, all I had to do was move the Ember.RSVP.all() to after a get() on the properties: 基本上,我所要做的就是将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));
}

So I needed to get() the properties that were belongsTo relationships before I save the model. 所以我需要在保存模型之前get()属于属性的属性。 I don't know is whether this is a bug or not. 我不知道这是不是一个bug。 Maybe someone with more knowledge about emberjs can help shed some light on that. 也许对emberjs有更多了解的人可以帮助阐明这一点。

See the question for more details, but the generic answer that I worked for me when saving a model with a belongsTo relationship (and you specifically need that relationship to be serialized) is to call .get() on the properties and then save() them in then() . 请参阅问题以获取更多详细信息,但是在保存具有belongsTo关系的模型时(我特别需要将该关系序列化),我为我工作的一般答案是在属性上调用.get()然后save()他们在then()

It boils down to this: 归结为:

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));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM