在保存到服务器之前更改 Ember 模型的值

Change an Ember model's value before saving to server

我有一个 Ember 模型,其中有一个我想显示和使用的字段,但在我保存它或从服务器检索它之前,我想 multiply/divide 它通过1000.

这意味着 UI 应始终使用较小的值,但将较大的值保存到服务器。同样,它应该从服务器检索一个更大的值,但在允许控制器、路由等使用它之前将其变小。

// models/my_model.js
import DS from 'ember-data';

export default DS.Model.extend({
    name: DS.attr('string'),
    value: DS.attr('number')
});

基本上,我希望我的应用程序将这些字段显示为:

/* my webpage */
Please enter name: "foo"
Please enter value: 5

但是当我发送请求时,它应该将它们发送为:

{
    "my_model": {
        "name": "foo",
        "value": 5000
    }
}

它应该以这种格式接收它们,然后通过除以 1000 反序列化该值。

请注意 multiplying/dividing 乘以 1000 是一个示例 - 我可能想要追加、前置、添加、减去等。


我尝试以不太优雅的方式进行此操作:

// Controller.js
actions: {
    save: function() {
        this.set('model.value', this.get('model.value') * 1000);
        this.get('model').save().then(
            /* stuff */
        );
        this.set('model.value', this.get('model.value') / 1000);
    }
}

但我对此并不满意,它会导致难以维护且容易出错的重复代码。

我有一个 RESTSerializer,但我不知道如何使用它来操作字段,并且在 the documentation 中找不到任何东西。也许我需要使用不同的序列化程序?我的目前基本上是空的。

// serializers/my_model.js
import DS from 'ember-data';

export default DS.RESTSerializer.extend({
    primaryKey: 'name',
});

我用自定义 serializenormalize(反序列化)方法解决了这个问题:

// serializers/my_model.js
import DS from 'ember-data';

export default DS.RESTSerializer.extend({
    normalizeResponse(store, primaryModelClass, payload) {
        payload.my_model.value /= 1000;
        return this._super(...arguments);
    },
    serialize() {
        let json = this._super(...arguments);
        json.value *= 1000;
        return json;
    }
});

这对我来说非常有用,而且非常灵活。

我建议在该用例中使用 Ember Data transform。与覆盖 Serializer 的 normalizeserialize 方法相比,它更具可重用性和更好的关注点分离。 Ember 数据转换可以看作是特定于属性的(反)序列化器。有一些内置转换:stringnumberbooleandate。您已经在使用其中的一些。

您应该从默认蓝图开始编写自定义序列化程序:ember generate transform currency。这将生成一个文件 app/transforms/currency.js 和相关的单元测试。转换扩展 DS.Transform class 并且必须实现 serializedeserialize 方法。他们将(反)序列化值作为参数,应该 return 相反。

重构您给出的示例作为转换的答案,如下所示:

// app/transforms/currency.js

import DS from 'ember-data';

export default DS.Transform.extend({
  deserialize(serialized) {
    return serialized / 1000;
  },

  serialize(deserialized) {
    return deserialized * 1000;
  }
});

可以这样使用:

// models/my_model.js
import DS from 'ember-data';

export default DS.Model.extend({
  name: DS.attr('string'),
  value: DS.attr('currency')
});

最大的好处是它可以根据需要应用于任意多的模型中的任意多的属性。它还可以在分离其他序列化问题时进行单元测试,并且可以作为 Ember 插件在应用程序之间轻松共享。