我正在为DreamFactory服务平台编写一个 Ember 数据适配器,并且遇到了一个问题,我认为与我的适配器有关。

更新现有记录时,由model.save()产生的promise会被拒绝,但会出现错误
Assertion Failed: An adapter cannot assign a new id to a record that already has an id. <App.Event311:1> had id: 1 and you tried to update it with null. This likely happened because your server returned data in response to a find or update that had a different id than the one you sent
问题是-对REST API的请求和从REST API返回的响应具有相同的ID!

请求(PUT)
{ "record": { "id": "1", "title": "Sample Event", "date": "7/20/2013", "type": "success", "desc": "My first sample event." }}
响应
{ "record": [ { "id": 1, "title": "Sample Event", "date": "7/20/2013", "type": "success", "desc": "My first sample event." } ]}
真正奇怪的是,记录仍然在数据库中的商店中正确更新!

我在http://emberjs.jsbin.com/mosek/1/edit上有一个正在工作的JSBin,可以说明问题。我的自定义适配器在GitHub上的https://github.com/ultimatemonty/ember-data-dreamfactory-adapter上。 JSBin和我的应用程序都使用Ember 1.7.0和ED 1.0.0-beta.9

编辑

JSBin附加到我个人托管的DreamFactory实例上-在允许从JSBin进行访问之外,我没有做任何事情,但是请保持谨慎:)

*编辑#2 *

可以在GitHub上的https://github.com/ultimatemonty/ember-data-dreamfactory-adapter/blob/master/lib/ember-data-dreamfactory-adapter.js#L106上访问updateRecord代码,但这是完整的参考方法:

updateRecord: function(store, type, record) {
    var data = {};
    var serializer = store.serializerFor(type.typeKey);
    serializer.serializeIntoHash(data, type, record);
    var adapter = this;

    return new Ember.RSVP.Promise(function(resolve, reject) {
        // hack to make DSP send back the full object
        adapter.ajax(adapter.buildURL(type.typeKey) + '?fields=*', "PUT", { data: data }).then(function(json){
            // if the request is a success we'll return the same data we passed in
            resolve(json);
        }, function(reason){
            reject(reason.responseJSON);
        });
    });
}

最佳答案

您使用的适配器/序列化器期望您返回一个没有类型的响应:

{
    "id": 1,
    "title": "Sample Event",
    "date": "7/20/2013",
    "type": "success",
    "desc": "My first sample event."
}

示例:http://emberjs.jsbin.com/tigiza/1/edit

您可以在extractSingle中看到它,它尝试将有效负载包装在具有指定类型的另一个对象中
EmberDreamFactoryAdapter.Serializer = DS.RESTSerializer.extend({

    extractArray: function(store, primaryType, payload) {
        var namespacedPayload = {};
        namespacedPayload[Ember.String.pluralize(primaryType.typeKey)] = payload.record;
        return this._super(store, primaryType, namespacedPayload);
    },

    extractSingle: function (store, primaryType, payload, recordId) {
        var namespacedPayload = {};
        namespacedPayload[primaryType.typeKey] = payload;
        return this._super(store, primaryType, namespacedPayload, recordId);
    },

您的回复如下所示:
{
    "record": [
        {
            "id": 1,
            "title": "Sample Event",
            "date": "7/20/2013",
            "type": "success",
            "desc": "My first sample event."
        }
    ]
}

然后序列化器启动,看起来像这样:
{
    event:{
       "record": [
          {
            "id": 1,
            "title": "Sample Event",
            "date": "7/20/2013",
            "type": "success",
            "desc": "My first sample event."
          }
      ]
   }
}

实际上,序列化器应具有以下外观:
{
  event:{
    "id": 1,
    "title": "Sample Event",
    "date": "7/20/2013",
    "type": "success",
    "desc": "My first sample event."
  }
}

您可以从第二个示例中看到,序列化程序将其包装在类型中,然后Ember Data说,嘿,给我id,所以它查看 undefined 的event.id,因为它位于event.record[0].id

10-08 09:20
查看更多