Record saves, promises rejection with REST adapter
I am writing an ember-data adapter for DreamFactory services platform and am facing a problem that I think is related to my adapter.
When you update an existing record, the promise resulting from model.save()
, always been rejected in error
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
Thing is - REST API request and response from REST API have the same ID!
Request (PUT)
{
"record": {
"id": "1",
"title": "Sample Event",
"date": "7/20/2013",
"type": "success",
"desc": "My first sample event."
}
}
Answer
{
"record": [
{
"id": 1,
"title": "Sample Event",
"date": "7/20/2013",
"type": "success",
"desc": "My first sample event."
}
]
}
It's really strange that the record still updates correctly in both the repository AND the database!
I have a working JSBin at http://emberjs.jsbin.com/mosek/1/edit that illustrates the problem. My custom adapter is on GitHub at https://github.com/ultimatemonty/ember-data-dreamfactory-adapter . JSBin as well as my app are using Ember 1.7.0 and ED 1.0.0-beta.9
EDIT
The JSBin is tied to my personal DreamFactory instance - I haven't done anything with it outside of the access permission from JSBin, but please be careful :)
* EDIT # 2 *
The code updateRecord
is available on GitHub at https://github.com/ultimatemonty/ember-data-dreamfactory-adapter/blob/master/lib/ember-data-dreamfactory-adapter.js#L106 , but here's the complete method for reference:
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);
});
});
}
source to share
The adapter / serializer used expects you to return a response without its type:
{
"id": 1,
"title": "Sample Event",
"date": "7/20/2013",
"type": "success",
"desc": "My first sample event."
}
Example: http://emberjs.jsbin.com/tigiza/1/edit
You can see it here in extractSingle
where it tries to wrap the payload in another object with the specified type
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);
},
Your answer looks like this:
{
"record": [
{
"id": 1,
"title": "Sample Event",
"date": "7/20/2013",
"type": "success",
"desc": "My first sample event."
}
]
}
Then the serializer runs and it looks like this:
{
event:{
"record": [
{
"id": 1,
"title": "Sample Event",
"date": "7/20/2013",
"type": "success",
"desc": "My first sample event."
}
]
}
}
When in fact, the serializer should look like this:
{
event:{
"id": 1,
"title": "Sample Event",
"date": "7/20/2013",
"type": "success",
"desc": "My first sample event."
}
}
You can see from the second example, the serializer wraps it in a type, then Ember Data says hey give me an id, so it looks like event.id
undefined because it lives underevent.record[0].id
source to share