Непрерывные атрибуты в EmberJS

Кто-нибудь знает способ указать для Ember model атрибут, который не сохраняется?

В основном мы загружаем некоторые метаданные, относящиеся к каждой модели, и отправляем эти данные в Ember через RESTAdapter в рамках модели. Эти метаданные можно изменить в нашем приложении, но это делается с помощью вызова AJAX. Как только вызов преуспеет, я хочу обновить это значение в модели без использования Ember в этом деле, изменив модель на uncommitted и сделав все, что бы она делала с transactions за кулисами.

У меня также есть проблема, что эти метаданные, которые не являются данными из записи базы данных model, передаются RESTAdapter обратно на сервер, что не ожидает этих значений. Я использую бэкэнд RoR, поэтому на сервере возникают ошибки, пытаясь назначить защищенные атрибуты, которые не предназначены для атрибутов вообще. Я знаю, что могу очистить данные, полученные на сервере, но я бы предпочел, чтобы клиент мог различать постоянные данные и вспомогательные данные.

Итак, к исходному вопросу: есть ли какая-либо альтернатива Ember-Data DS.attr('...'), которая будет указывать непостоянный атрибут?

Ответ 1

Когда этот PR будет объединен, можно будет пометить свойства как readOnly. Но до тех пор есть некоторые обходные пути к этому, например. переопределяя ваш метод addAttributes в адаптере и обрабатывая ваши специальные свойства, вот пример, как это могло бы выглядеть:

Определите модель, добавив новую опцию readOnly:

App.MyModel = DS.Model.extend({
  myMetaProperty: DS.attr('metaProperty', {readOnly: true})
});

а затем на адаптере:

App.Serializer = DS.RESTSerializer.extend({
   addAttributes: function(data, record) {
     record.eachAttribute(function(name, attribute) {
       if (!attribute.options.readOnly) {
         this._addAttribute(data, record, name, attribute.type);
       }
     }, this);
   }
 });

то, что это делает, - это цикл над атрибутами вашей модели, и когда он находит атрибут с флагом readOnly, он пропускает свойство.

Я надеюсь, что этот механизм работает для вашего использования.

Ответ 2

Другие ответы на этот вопрос работают с версиями данных Ember до 0,13 и больше не работают. Для Ember data 1.0 beta 3 вы можете:

App.ApplicationSerializer = DS.RESTSerializer.extend({
  serializeAttribute: function(record, json, key, attribute) {
    if (attribute.options.transient) {
      return;
    }
    return this._super(record, json, key, attribute);
  }
});

Теперь вы можете использовать переходные атрибуты:

App.User = DS.Model.extend({
  name: DS.attr('string', {transient: true})
});

Эти атрибуты не будут отправляться на сервер при сохранении записей.

Ответ 3

Следуя этому answer, чтобы предотвратить сериализацию поля, переопределите сериализатор по умолчанию для вашей модели:

В app/serializers/person.js:

export default DS.JSONSerializer.extend({
  attrs: {
    admin: { serialize: false }
  }
});

Смотрите здесь для источника PR. Это решение работает в Ember Data 2 и должно работать и в более старых версиях.

Ответ 4

Update

Этот ответ, скорее всего, устарел с текущими выпусками Ember Data. Я бы ничего не использовал в своем ответе.


Я отвечаю на этот вопрос для справки, и потому, что в вашем комментарии указано, что запись остается isDirty, но вот мое решение для только для чтения, non-persistent strong > , не-грязные.

Переопределение метода addAtributes в вашем Serializer предотвращает отправку атрибутов readOnly на сервер, что, вероятно, именно то, что вы хотите, но вам нужно расширить (или reopen) ваш адаптер, чтобы переопределить dirtyRecordsForAttributeChange, чтобы предотвратить загрязнение записи:

App.CustomAdapter = DS.RESTAdapter.extend({
  dirtyRecordsForAttributeChange: function(dirtySet, record, attrName, newValue, oldValue) {
    meta = record.constructor.metaForProperty(attrName);
    if (meta && meta.options.readOnly) { return; }
    this._super.apply(this, arguments);
  };
});

Затем вы можете использовать атрибуты readOnly, например:

App.User = DS.Model.extend({
  name: DS.attr('string', {readOnly: true})
});

user = App.User.find(1);      # => {id: 1, name: 'John Doe'}
user.set('name', 'Jane Doe'); #
user.get('isDirty')           # => false

Эта настройка работает для меня.