Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactored InvalidError handling into a serializer concern. #2392

Merged
merged 1 commit into from
Oct 16, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 1 addition & 13 deletions packages/activemodel-adapter/lib/system/active_model_adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {pluralize} from "ember-inflector";
@module ember-data
*/

var forEach = Ember.EnumerableUtils.forEach;
var decamelize = Ember.String.decamelize,
underscore = Ember.String.underscore;

Expand Down Expand Up @@ -142,18 +141,7 @@ var ActiveModelAdapter = RESTAdapter.extend({
var error = this._super(jqXHR);

if (jqXHR && jqXHR.status === 422) {
var response = Ember.$.parseJSON(jqXHR.responseText),
errors = {};

if (response.errors !== undefined) {
var jsonErrors = response.errors;

forEach(Ember.keys(jsonErrors), function(key) {
errors[Ember.String.camelize(key)] = jsonErrors[key];
});
}

return new InvalidError(errors);
return new InvalidError(Ember.$.parseJSON(jqXHR.responseText));
} else {
return error;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ test('buildURL - decamelizes names', function() {
});

test('ajaxError - returns invalid error if 422 response', function() {
var error = new DS.InvalidError({ name: "can't be blank" });
var error = new DS.InvalidError({ errors: { name: "can't be blank" } });

var jqXHR = {
status: 422,
Expand All @@ -32,7 +32,7 @@ test('ajaxError - returns invalid error if 422 response', function() {
});

test('ajaxError - invalid error has camelized keys', function() {
var error = new DS.InvalidError({ firstName: "can't be blank" });
var error = new DS.InvalidError({ errors: { firstName: "can't be blank" } });

var jqXHR = {
status: 422,
Expand Down
10 changes: 8 additions & 2 deletions packages/ember-data/lib/adapters/rest_adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -697,19 +697,25 @@ export default Adapter.extend({
},

/**
Takes an ajax response, and returns a relevant error.
Takes an ajax response, and returns an error payload.

Returning a `DS.InvalidError` from this method will cause the
record to transition into the `invalid` state and make the
`errors` object available on the record.

This function should return the entire payload as received from the
server. Error object extraction and normalization of model errors
should be performed by `extractErrors` on the serializer.

Example

```javascript
App.ApplicationAdapter = DS.RESTAdapter.extend({
ajaxError: function(jqXHR) {
var error = this._super(jqXHR);

if (jqXHR && jqXHR.status === 422) {
var jsonErrors = Ember.$.parseJSON(jqXHR.responseText)["errors"];
var jsonErrors = Ember.$.parseJSON(jqXHR.responseText);

return new DS.InvalidError(jsonErrors);
} else {
Expand Down
45 changes: 45 additions & 0 deletions packages/ember-data/lib/serializers/json_serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,16 @@ export default Ember.Object.extend({
delete hash[primaryKey];
},

/**
@method normalizeErrors
@private
*/
normalizeErrors: function(type, hash) {
this.normalizeId(hash);
this.normalizeAttributes(type, hash);
this.normalizeRelationships(type, hash);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ahacking,

We're updating our app to latest Ember-Data and we've been having issues in our error processing because of this. When using polymorphic relationships, normalizeRelationships will inspect the hash for a type property. Since this is an error payload, the type property won't be set.

Here's a workaround implementation which works great for us. Do you see any issue with it? I'm thinking of opening a PR with it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you open an issue for this please as well, just so we can track it

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: #3017

},

/**
Looks up the property key that was set by the custom `attr` mapping
passed to the serializer.
Expand Down Expand Up @@ -970,6 +980,41 @@ export default Ember.Object.extend({
}
},

/**
`extractErrors` is used to extract model errors when a call is made
to `DS.Model#save` which fails with an InvalidError`. By default
Ember Data expects error information to be located on the `errors`
property of the payload object.

Example

```javascript
App.PostSerializer = DS.JSONSerializer.extend({
extractErrors: function(store, type, payload, id) {
if (payload && typeof payload === 'object' && payload._problems) {
payload = payload._problems;
this.normalizeErrors(type, payload);
}
return payload;
}
});
```

@method extractErrors
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} payload
@param {String or Number} id
@return {Object} json The deserialized errors
*/
extractErrors: function(store, type, payload, id) {
if (payload && typeof payload === 'object' && payload.errors) {
payload = payload.errors;
this.normalizeErrors(type, payload);
}
return payload;
},

/**
`keyForAttribute` can be used to define rules for how to convert an
attribute name in your model to a key in your JSON.
Expand Down
6 changes: 5 additions & 1 deletion packages/ember-data/lib/system/adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ var errorProps = [
transition to the `invalid` state and the errors will be set to the
`errors` property on the record.

This function should return the entire payload as received from the
server. Error object extraction and normalization of model errors
should be performed by `extractErrors` on the serializer.

Example

```javascript
Expand All @@ -31,7 +35,7 @@ var errorProps = [
var error = this._super(jqXHR);

if (jqXHR && jqXHR.status === 422) {
var jsonErrors = Ember.$.parseJSON(jqXHR.responseText)["errors"];
var jsonErrors = Ember.$.parseJSON(jqXHR.responseText);
return new DS.InvalidError(jsonErrors);
} else {
return error;
Expand Down
4 changes: 3 additions & 1 deletion packages/ember-data/lib/system/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -1869,7 +1869,9 @@ function _commit(adapter, store, operation, record) {
return record;
}, function(reason) {
if (reason instanceof InvalidError) {
store.recordWasInvalid(record, reason.errors);
var errors = serializer.extractErrors(store, type, reason.errors, get(record, 'id'));
store.recordWasInvalid(record, errors);
reason = new InvalidError(errors);
} else {
store.recordWasError(record, reason);
}
Expand Down