保存失败后如何恢复模型?

时间:2017-05-04 08:51:59

标签: ember.js ember-data

我们正在使用RectTransforms来处理表单中的数据。数据流通常如下:input -> changeset -> model -> server -> model -> changeset -> input。用户更改一些输入,这些输入反映在变更集中并经过验证。当用户按下submit时,变更集将被烘焙到模型中,然后保存。

这就是问题所在。如果服务器拒绝接受更改,那么我们最终会得到处于损坏状态的模型。为了解决这个问题,我们实施了自定义save方法来模仿model.save所做的事情。

基本思想是我们从变更集中获取更改并将其提交给服务器asi,如果我们只是保存模型。如果失败了,那么基本上没有任何反应。变更集保持脏,底层模型不变。但是,当保存成功时,我们使用从服务器返回的数据来更新基础实体,方法基本上与正常保存实体时商店所做的相同。

这适用于属性和关系。唯一的问题是当我们需要检查可能在保存之后发生变化的关系时,他们会懒得更新它们。

非常感谢任何帮助或想法。

/*
 * Saves an object by saving changes taken from a changeset.
 * Updates the target object if the operation succeeds.
 * @param changeset the changeset to save
 * @return {Promise} a promise that resolves to an object returned by the server
 */
saveChangeset(changeset) {
  const record = changeset.get('_content'); // not entirely a public field
  const id = record.get('id');
  const constructor = record.get('constructor');
  const modelName = constructor.modelName;

  const snapshot = changesetToSnapshot(changeset);
  const operation = record.get('isNew') ? 'createRecord' : 'updateRecord';

  record._internalModel.adapterWillCommit();
  return this.adapterFor(modelName)[operation](this, constructor, snapshot)
    .then(res => {
      // propagate the changes
      const model = this.modelFor(modelName);
      const serializer = this.serializerFor(modelName);
      const payload = serializer.normalizeResponse(this, model, res, id, operation);
      if (payload.included) {
        this.push({data: payload.included});
      }
      this.didSaveRecord(record._internalModel, {data: payload.data});
      changeset.rollback();
      return res;
    });
},


/**
 * Creates s snapshot-like object based on a changeset.
 */
export default function changesetToSnapshot(changeset) {
  const model = changeset.get('_content'); // not entirely a public field
  const isNew = model.get('isNew');
  const id = model.get('id');
  const constructor = model.get('constructor');
  const modelName = constructor.modelName;

  const changes = {};
  changeset.get('changes').forEach(change => {
    changes[change.key] = null; // The value does not matter
  });

  const filterByName = fn => (name, meta) => { // eslint-disable-line func-style
    if (name in changes) {
      fn(name, meta);
    }
  };

  const fieldFilter = isNew ? fn => fn : filterByName;

  return { // emulate a snapshot
    _isChangeset: true,
    type: constructor,
    record: model,
    modelName,
    id,
    eachAttribute: fn => model.eachAttribute(fieldFilter(fn)),
    eachRelationship: fn => model.eachRelationship(fieldFilter(fn)),
    attr: key => changeset.get(key),
    belongsTo(key, options) {
      assert('Snapshot from changeset can only return the id of a belongsTo relationship, not a snapshot of it', options && options.id);
      return get(changeset, key + '.id');
    },
    hasMany(key, options) {
      assert('Snapshot from changeset can only return the ids of a hasMany relationship, not an array of snapshots', options && options.ids);
      return changeset.get(key).map(e => e.get('id'));
    },
  };
}

0 个答案:

没有答案