web-dev-qa-db-ja.com

Ember.jsデータ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の使用は正しい方向に進んでいるようですが。

42
michaelvobrien

今週末、私は同じことを理解しようとしていました。ルークの発言を離れて、私は 最新のコミット (12月11日)のember-dataソースを詳しく調べました。

TLDR; ember-data update/createエラーを処理するには、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コールバックエラー関数が指定されています 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.recordWasInvalidおよびstore.recordWasError(定義済み ここ )は、レコード(DS.Model)のハンドラーを呼び出します。無効な場合は、アダプターからのエラーメッセージを引数として渡します。

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

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

DS.Model.adapterDidInvalidateおよびadapterDidError(定義 ここ )は単に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を返すためのダミー関数です。 ここ を参照)

したがって、結論は、これらのケースを処理するためにモデルでbecameInvalidおよびbecameErrorの関数を定義する必要があるだけです。

これが他の誰かを助けることを願っています。ドキュメントは確かに現在これを反映していません。

42
Sherwin Yu

DS.RESTAdapterthis commit でエラー処理が少し増えましたが、まだエラー処理についての推奨事項はありません。

(私が行ったように)ember-dataを使用してアプリを本番環境で運用する意欲的または夢中になっている場合は、APIで障害が発生する可能性が極めて低いことを確認することをお勧めします。つまり、クライアント側でデータを検証します。

うまくいけば、我々はこの質問を今後数ヶ月でより良い答えで更新することができます。

8
Luke Melia

私はそのような状況に遭遇しました、これがすでにどこかで説明されているかどうかはわかりません。

使ってます:

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

したがって、このようにして、属性をクライアント側で検証し、サーバー側で再度検証することができます。

免責事項:これが最善の方法かどうかはわかりません!

3
sabithpocker

現在、Ember-Dataには適切なソリューションがないため、DS.ModelにapiErrorsプロパティを追加して独自のソリューションを作成し、次にRestAdapterサブクラスに(独自のソリューションが既に必要です)エラーコールバックをAjaxはcreateRecordおよびupdateRecordを呼び出し、エラーを保存し、モデルを「無効な」状態にします。これは、クライアント側またはサーバー側の検証が失敗したことを意味します。

コードスニペットは次のとおりです。

これは、application.jsまたは他のいくつかの最上位ファイルに移動できます。

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

これは、RestAdapterサブクラスのcreateRecordおよびupdateRecordのエラーコールバックに含まれます。

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');
}
2
webjprgm