使用 Ember.js Data RESTAdapter 时应如何处理错误?



ember-data.js: https://github.com/emberjs/data/tree/0396411e39df96c8506de3182c81414c1d0eb981

简而言之,当出现错误时,我想在视图中显示错误消息,然后用户可以 1) 取消,这将回滚事务 2) 更正输入错误并成功提交事务,在服务器上传递验证。

下面是源代码的代码片段。它不包括错误回调。

updateRecord: function(store, type, record) {
var id = get(record, 'id');
var root = this.rootForType(type);
var data = {};
data[root] = this.toJSON(record);
this.ajax(this.buildURL(root, id), "PUT", {
data: data,
context: this,
success: function(json) {
this.didUpdateRecord(store, type, record, json);
}
});
},

总体而言,从服务器接收错误并更新视图的流程是什么?似乎错误回调应该将模型置于isError状态,然后视图可以显示相应的消息。此外,交易应该保持脏污。这样,事务可以使用rollback

不过,使用store.recordWasInvalid似乎正朝着正确的方向发展。

这个周末我试图弄清楚同样的事情。离开 Luke 所说的,我仔细查看了最新提交(12 月 11 日)的 ember 数据源。

TLDR; 要处理 ember 数据更新/创建错误,只需在DS.Model实例上定义becameError()becameInvalid(errors)。由 RESTadapter 的 AJAX 错误回调触发的级联最终将调用您定义的这些函数。

例:

App.Post = DS.Model.extend
title: DS.attr "string"
body: DS.attr "string"
becameError: ->
# handle error case here
alert 'there was an error!'
becameInvalid: (errors) ->
# record was invalid
alert "Record was invalid because: #{errors}"

以下是源代码的完整演练:

在 REST 适配器中,AJAX 回调错误函数如下所示:

this.ajax(this.buildURL(root, id), "PUT", {
data: data,
context: this,
success: function(json) {
Ember.run(this, function(){
this.didUpdateRecord(store, type, record, json);
});
},
error: function(xhr) {
this.didError(store, type, record, xhr);
}
});

didError 在这里定义,它依次调用存储的 recordWasInvalid 或 recordWasError 根据响应:

didError: function(store, type, record, xhr) {
if (xhr.status === 422) {
var data = JSON.parse(xhr.responseText);
store.recordWasInvalid(record, data['errors']);
} else {
store.recordWasError(record);
}
},

反过来,store.recordWasInvalidstore.recordWasError(此处定义)调用记录(DS.模型)的处理程序。在无效的情况下,它会将来自适配器的错误消息作为参数传递。

recordWasInvalid: function(record, errors) {
record.adapterDidInvalidate(errors);
},
recordWasError: function(record) {
record.adapterDidError();
},

DS.Model.adapterDidInvalidateadapterDidError(定义在这里)只是send('becameInvalid', errors)send('becameError'),最终将我们引向此处的处理程序:

didLoad: Ember.K,
didUpdate: Ember.K,
didCreate: Ember.K,
didDelete: Ember.K,
becameInvalid: Ember.K,
becameError: Ember.K,

(Ember.K 只是一个用于返回this的虚拟函数。看这里)

因此,结论是,您只需要在模型上定义becameInvalidbecameError函数即可处理这些情况。

希望这对其他人有所帮助;文档现在肯定没有反映这一点。

DS.RESTAdapter在这个提交中得到了更多的错误处理,但我们还没有达到一个很好的错误处理建议的地步。

如果你雄心勃勃/疯狂到今天使用余烬数据将应用程序投入生产(就像我一样!),最好确保你的API失败的可能性极低。 即在客户端验证您的数据。

希望我们能在未来几个月内用更好的答案来更新这个问题。

我刚刚遇到了这种情况,不确定这是否已经在任何地方解释过。

我正在使用:

Em.VERSION : 1.0.0
DS.VERSION : "1.0.0-beta.6"
Ember Validations (dockyard) : Version: 1.0.0.beta.1
Ember I18n

该模型最初与验证混合混合。

App.Order = DS.Model.extend(Ember.Validations.Mixin, {
.....
someAttribute : DS.attr('string'),
/* Client side input validation with ember-validations */
validations : {
someAttribute : {
presence : {
message : Ember.I18n.t('translations.someAttributeInputError')
}
}
}
});

在模板中,添加了相应的车把。(请注意,在输入验证的情况下,Ember 验证会自动将错误添加到model.errors.<attribute>,我也将在服务器验证中使用相同的权衡)

<p>{{t 'translations.myString'}}<br>
{{view Ember.TextField valueBinding="attributeName"}}
{{#if model.errors.attributeName.length}}<small class="error">{{model.errors.attributeName}}</small>{{/if}}
</p

现在,我们将保存Order

App.get('order').save().then(function () {
//move to next state?
}, function(xhr){
var errors = xhr.responseJSON.errors;
for(var error in errors){ //this loop is for I18n
errors[error] = Ember.I18n.t(errors[error]);
}
controller.get('model').set('errors', errors); //this will overwrite current errors if any
});

现在,如果服务器抛出一些验证错误,则返回的数据包是

{"errors":{"attributeName1":"translations.attributeNameEror",
"another":"translations.anotherError"}}
status : 422

使用状态很重要422

因此,这样,您的属性可以在客户端和服务器端再次验证。

免责声明:我不确定这是否是最好的方法!

由于库存 Ember-Data 目前没有好的解决方案,我通过向 DS 添加apiErrors属性来制作自己的解决方案。模型,然后在我的 RestAdapter 子类中(我已经需要我自己的子类),我在 AjaxupdateRecordcreateRecord调用中添加了错误回调,用于保存错误并将模型置于"无效"状态,这应该意味着客户端或服务器端验证失败。

以下是代码片段:

这可以放在应用程序中.js或者其他一些顶级文件中:

DS.Model.reopen({
// Added for better error handling on create/update
apiErrors: null
});

这出现在 RestAdapter 子类中createRecordupdateRecord的错误回调中:

error: function(xhr, textStatus, err) {
console.log(xhr.responseText);
errors = null;
try {
errors = JSON.parse(xhr.responseText).errors;
} catch(e){} //ignore parse error
if(errors) {
record.set('apiErrors',errors);
}
record.send('becameInvalid');
}

最新更新