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

时间:2012-10-19 06:48:23

标签: ember.js ember-data

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正朝着正确的方向发展。

4 个答案:

答案 0 :(得分:42)

本周末,我试图想出同样的事情。关闭卢克所说的,我仔细研究了latest commit(12月11日)的余烬数据来源。

<强> TLDR;要处理余烬数据更新/创建错误,只需在becameError()实例上定义becameInvalid(errors)DS.Model即可。由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回调错误函数被赋予here

   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定义为here,它依次根据响应调用商店的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(已定义here)会调用记录(DS.Model)的处理程序。在无效的情况下,它将来自适配器的错误消息作为参数传递。

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

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

DS.Model.adapterDidInvalidateadapterDidError(已定义here)只是send('becameInvalid', errors)send('becameError'),最终将我们带到处理程序here

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

(Ember.K只是一个用于返回this的虚函数。请参阅here

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

希望这有助于其他人;文档当然没有反映这一点。

答案 1 :(得分:8)

DS.RESTAdapterthis commit中进行了更多的错误处理,但我们还没有达到我们对错误处理的强烈建议。

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

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

答案 2 :(得分:3)

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

我正在使用:

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

该模型最初与Validation mixin混合。

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

非常重要

因此,您的属性可以在客户端验证,也可以在服务器端验证。

免责声明:我不确定这是否是最佳方式!

答案 3 :(得分:2)

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

以下是代码段:

这可以放在application.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');
}