我正在使用Ember Data,我似乎无法获得模型的'errors'属性来填充来自我的REST API的错误消息。我非常关注本指南中的示例:
http://emberjs.com/api/data/classes/DS.Errors.html
我的应用看起来像这样:
window.App = Ember.Application.create();
App.User = DS.Model.extend({
username: DS.attr('string'),
email: DS.attr('string')
});
App.ApplicationRoute = Ember.Route.extend({
model: function () {
return this.store.createRecord('user', {
username: 'mike',
email: 'invalidEmail'
});
},
actions: {
save: function () {
this.modelFor(this.routeName).save();
}
}
});
我的API会返回:
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Content-Length: 125
{
"errors": {
"username": ["Username is taken!"],
"email": ["Email is invalid."]
}
}
在模型上调用save()后,我在用户模型上看到了这一点:
user.get('isError') // true
user.get('errors.messages') // []
即使模型正确地注册了isError属性,我也似乎无法填充错误消息。我怎样才能让它发挥作用?我正在研究Ember Data版本1.0.0-beta.8.2a68c63a的最新beta版本
答案 0 :(得分:10)
这个区域肯定缺少文档,除非您使用活动模型适配器,否则不会填充错误。
这是一个有效的例子,也请查看Ember: error.messages does not show server errors on save我说同样的事情
http://jsbin.com/motuvaye/24/edit
您可以通过覆盖ajaxError
并复制活动模型适配器的工作方式,在RESTAdapter上轻松实现它。
App.ApplicationAdapter = DS.RESTAdapter.extend({
ajaxError: function(jqXHR) {
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;
Ember.EnumerableUtils.forEach(Ember.keys(jsonErrors), function(key) {
errors[Ember.String.camelize(key)] = jsonErrors[key];
});
}
return new DS.InvalidError(errors);
} else {
return error;
}
}
});
答案 1 :(得分:8)
我对Ember Data的errors.messages属性有过长期非常令人沮丧的经历,所以我想我总结了我的所有发现,以防其他人试图使用此功能。
1)文档已过期
正如@ kingpin2k在他的回答中提到的那样,http://emberjs.com/api/data/classes/DS.Errors.html的文件已经过时了。他们在该页面上提供的示例仅在您使用DS.ActiveModelAdapter时才有效。如果您使用的是默认的DS.RESTAdapter,那么您需要执行类似的操作。请注意,我更喜欢这种更简单的方法,而不仅仅是复制ActiveModelAdapter的ajaxError实现:
App.ApplicationAdapter = DS.RESTAdapter.extend({
ajaxError: function (jqXHR) {
this._super(jqXHR);
var response = Ember.$.parseJSON(jqXHR.responseText);
if (response.errors)
return new DS.InvalidError(response.errors);
else
return new DS.InvalidError({ summary: 'Error connecting to the server.' });
}
});
2)您必须提供拒绝回拨
这很奇怪,但是当你在你的模型上调用save()时,你需要提供一个拒绝回调,否则,你将得到一个未被捕获的'后端拒绝提交'异常,JavaScript将停止执行。我不知道为什么会这样。
没有拒绝回调的示例。这将导致异常:
user.save().then(function (model) {
// do something
});
拒绝回调的示例。一切都会运作良好:
user.save().then(function (model) {
// do something
}, function (error) {
// must supply reject callback, otherwise Ember will throw a 'backend rejected the commit' error.
});
3)默认情况下,只有属于模型的错误属性才会在errors.messages中注册。例如,如果这是您的模型:
App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string')
});
...如果这是你的错误有效载荷:
{
"errors": {
"firstName":"is required",
"summary":"something went wrong"
}
}
然后摘要不会出现在user.get('errors.messages')中。可以在Ember Data的adapterDidInvalidate方法中找到此问题的根源。它使用this.eachAttribute和this.eachRelationship将错误消息的注册限制为仅属于模型的那些。
adapterDidInvalidate: function(errors) {
var recordErrors = get(this, 'errors');
function addError(name) {
if (errors[name]) {
recordErrors.add(name, errors[name]);
}
}
this.eachAttribute(addError);
this.eachRelationship(addError);
}
这里有关于此问题的讨论:https://github.com/emberjs/data/issues/1877
在Ember团队修复此问题之前,您可以通过创建一个覆盖默认的adapterDidInvalidate实现的自定义基本模型来解决此问题,并且所有其他模型都从中继承:
基础模型:
App.Model = DS.Model.extend({
adapterDidInvalidate: function (errors) {
var recordErrors = this.get('errors');
Ember.keys(errors).forEach(function (key) {
recordErrors.add(key, errors[key]);
});
}
});
用户模型:
App.User = App.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string')
});
4)如果从适配器的ajaxError(我们上面覆盖的那个)返回DS.InvalidError,那么你的模型将停留在'isSaving'状态,你将无法摆脱它。 强>
如果您使用的是DS.ActiveModelAdapter,也会出现此问题。
例如:
user.deleteRecord();
user.save().then(function (model) {
// do something
}, function (error) {
});
当服务器响应错误时,模型的isSaving状态为true,我无法在不重新加载页面的情况下重置它。
更新时间:2014-10-30 对于那些正在努力解决DS.Errors的人来说,这是一篇很好的博客文章,总结了这一点:http://alexspeller.com/server-side-validations-with-ember-data-and-ds-errors/
答案 2 :(得分:4)
更新:Ember Data 2.x
上述回复仍然有些相关,而且通常非常有用,但现在已经过时了Ember Data 2.x(撰写本文时的v2.5.1)。使用较新版本的Ember Data时,需要注意以下几点:
DS.RESTAdapter
在2.x中不再具有ajaxError
功能。现在由RESTAdapter.handleResponse()
处理。如果需要任何特殊处理或格式化错误,则可以覆盖此方法。 RESTAdapter.handleResponse source code DS.Errors
和DS.Model.errors
(这是DS.Errors的一个实例)的文档目前有点误导。 仅在响应中的错误符合JSON API错误对象规范时才有效。这意味着如果您的API错误对象遵循任何其他格式,它将毫无帮助或可用。不幸的是,这种行为目前无法像Ember Data中的许多其他内容一样被覆盖,因为此行为是在DS.Model内的Ember的InternalModel类中的私有API中处理的。DS.InvalidError
时才会使用422
。如果您的API使用不同的状态代码来表示无效请求的错误,则可以覆盖RESTAdapter.isInvalid()
以自定义哪些状态代码(或错误响应的其他部分)以检查为InvalidError
。isInvalid()
以始终返回false,以便Ember Data始终创建更通用的DS.AdapterError
instead。然后在DS.Model.adapterError
上设置此错误,并根据需要从那里开始使用。DS.AdapterError.errors
包含API响应的errors
键上返回的内容。