Handling Rails HEAD 204 on update
This article was provided by kaisersly.
The problem
Rails default response to an update is:
head :no_content
which is an empty response with a status code of 204 (NO CONTENT).
Even if you write:
def update
if @resource.update(params)
render @resource, status: :ok
end
end
you'll still get an empty response (HEAD) with a 204 status code.
When you do a DS.find('resource', id)
, js-data will send a PUT request. It will then receive a HEAD 204 response and will try to inject the payload in the cache. So it will perform something like:
DS.inject('resource', JSON.parse('')) // the '' comes from the empty payload in the HEAD response
and will throw an error (you can't inject an empty object).
The Rails solution
This stackoverflow question provides the Rails way to change the response.
The js-data solution
Step 1 : disable the injection
You can disable the injection when you update a resource.
Resource.update(1234, { foo: 'bar' }, { cacheResponse: false }).then(...);
You can disable it app wide:
var store = new JSData.DS({
beforeUpdate: function (Resource, data, cb) {
resource.cacheResponse = false;
cb(null, data);
}
});
or resource wide:
var Resource = DS.defineResource({
name: 'resource',
beforeUpdate: function (Resource, data, cb) {
resource.cacheResponse = false;
cb(null, data);
};
});
If you use Angular (app wide) :
angular.module('myApp', ['js-data'])
.config(function (DSProvider) {
DSProvider.defaults.beforeUpdate = function (resource, data, cb) {
resource.cacheResponse = false;
cb(null, data);
};
});
Step 2 : inject the resource manually
You just disabled the injection. If you stop here, this will happens:
var myResource = DS.get('resource', 1);
// { name: 'my resource', id: 1 }
myResource.name = 'a new name'
myResource.DSSave();
myResource = DS.get('resource', 1);
// still { name: 'my resource', id: 1 } because the updated resource wasn't injected
You have to inject the resource when the update is successful :
var myResource = DS.get('resource', 1);
// { name: 'my resource', id: 1 }
myResource.name = 'a new name'
myResource.DSSave().then(function (data) { // data, the payload of the response, is empty
DS.inject('resource', myResource);
});
myResource = DS.get('resource', 1);
// { name: 'a new name', id: 1 }