Ember.js 余烬数据模型';s errors属性(DS.errors)未填充

Ember.js 余烬数据模型';s errors属性(DS.errors)未填充,ember.js,ember-data,Ember.js,Ember Data,我使用的是余烬数据,似乎无法使用RESTAPI中的错误消息填充模型的“errors”属性。我基本上遵循了本指南中的示例: 我的应用程序如下所示: window.App = Ember.Application.create(); App.User = DS.Model.extend({ username: DS.attr('string'), email: DS.attr('string') }); App.Applicatio

我使用的是余烬数据,似乎无法使用RESTAPI中的错误消息填充模型的“errors”属性。我基本上遵循了本指南中的示例:

我的应用程序如下所示:

    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') // []
App.User = App.Model.extend({
    firstName: DS.attr('string'),
    lastName: DS.attr('string')
});

即使模型正确地注册了isError属性,我似乎也无法获得要填充的错误消息。我怎样才能让它工作?我正在开发Ember数据版本1.0.0-beta.8.2a68c63a的最新beta版。这方面的文档肯定没有,除非使用活动模型适配器,否则不会填充错误

这里有一个例子,它的工作,也看看我说同样的事情

通过覆盖
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;
    }
  }
});


我对余烬数据的errors.messages属性有一段漫长而令人沮丧的经历,因此我想在此总结一下我的所有发现,以防其他人尝试使用此功能

1)文档已过时

正如@kingpin2k在其回答中提到的,处的文档已过时。只有在使用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()时,您需要提供拒绝回调,否则,您将得到一个未捕获的“backend rejected the commit”异常,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)默认情况下,只有作为模型一部分的错误属性才会在错误消息中注册。例如,如果这是您的模型:

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数据的AdapterDidValidate方法中找到。它使用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);
  }
这里有一个关于这个问题的讨论:

在Ember团队解决此问题之前,您可以通过创建一个覆盖默认AdapterDidValidate实现的自定义基础模型来解决此问题,并且您的所有其他模型都从中继承:

基本型号:

App.Model = DS.Model.extend({
    adapterDidInvalidate: function (errors) {
        var recordErrors = this.get('errors');
        Ember.keys(errors).forEach(function (key) {
            recordErrors.add(key, errors[key]);
        });
    }
});
用户模型:

user.get('isError') // true
user.get('errors.messages') // []
App.User = App.Model.extend({
    firstName: DS.attr('string'),
    lastName: DS.attr('string')
});
4)如果您从适配器的ajaxError返回DS.InvalidError(我们在上面覆盖的错误),那么您的模型将处于“正在保存”状态,您将无法摆脱它。

如果使用DS.ActiveModelAdapter,也会出现此问题

例如:

    user.deleteRecord();
    user.save().then(function (model) {
        // do something
    }, function (error) {

    });
当服务器响应错误时,模型的isSaving状态为true,我无法在不重新加载页面的情况下重置它

更新:2014-10-30
对于那些正在与DS.Errors作斗争的人来说,这里有一篇很好的博文总结了这一点:

更新:Ember Data 2.x

上面的回答仍然有一定的相关性,通常非常有用,但现在对于Ember Data 2.x(撰写本文时为v2.5.1)来说已经过时了。使用较新版本的余烬数据时,请注意以下几点:

  • DS.RESTAdapter
    在2.x中不再具有
    ajaxError
    功能。这件事现在由我们来处理。如果需要对错误进行任何特殊处理或格式化,则可以重写此方法
  • 关于
    DS.Errors
    DS.Model.Errors
    (这是DS.Errors的一个实例)的文档目前有点误导。它仅在响应中的错误符合JSON API错误对象规范时才起作用。这意味着,如果您的API错误对象遵循任何其他格式,那么它将毫无用处。不幸的是,这个行为目前不能像Ember数据中的许多其他东西一样被覆盖,因为这个行为是在DS.Model中Ember的InternalModel类的私有API中处理的
  • DS.InvalidError
    仅在响应状态代码默认为
    422
    时使用。如果您的API使用不同的状态代码来表示无效请求的错误,您可以重写
    RESTAdapter.isInvalid()
    ,以自定义要检查的状态代码(或错误响应的其他部分)以表示
    InvalidError
  • 作为替代方法,您可以覆盖
    isInvalid()
    以始终返回false,这样余烬数据将始终创建更通用的。然后在DS.Model.adapterError上设置此错误,并可根据需要从那里利用此错误
  • DS.AdapterError.errors
    包含API响应的
    errors
    键上返回的内容

您使用的是ActiveModelAdapter吗?不,我使用的是默认的DS.RestaAdapter。至少我想我用的是这个。我的问题中列出了我所有的JavaScript代码。如果我不指定任何内容,我想Ember数据默认为DS.RESTAdapter。哇,我只是在这上面浪费了几个小时。谢谢你澄清这个问题。您知道这是否只是ActiveModelAdapter的一个设计特性吗?或者他们打算把它移植到RestaAdapter上吗?可能是这样的,我认为它最初是因为rails活动模型适配器的内置特性(我不确定,我不使用它),至少它可以被记录下来,在r上实现起来相当简单