Можно ли с помощью emberfire указать, что атрибуту временной метки в модели должно быть присвоено значение Firebase.ServerValue.TIMESTAMP?

У меня есть модель с атрибутом timestamp. Когда записи создаются на сервере, я бы хотел, чтобы значение этого атрибута инициализировалось значением со стороны сервера, а не клиента, предоставляющего значение, чтобы эти временные метки были согласованы для разных клиентов.

Если бы я использовал API Firebase напрямую, я понимаю, что мог бы использовать специальный токен Firebase.ServerValue.TIMESTAMP для достижения этой цели. Но я не могу понять, как это сделать с помощью ember-data и адаптера emberfire.

2 ответа

Извините, я знаю, что уже поздно, но я столкнулся с той же проблемой.

Вы можете определить пользовательский тип атрибута с помощью DS.Transform, который просто передает это значение, когда вы его сериализуете. Я только что назвал свою метку времени.

// transforms/timestamp.js
/* global Firebase */
import DS from 'ember-data';

export default DS.DateTransform.extend({
    serialize: function(date) {
        if(date === Firebase.ServerValue.TIMESTAMP){
            return date;
        }
        return this._super(date);
    }
});

Тогда вы можете использовать его примерно так, как ожидалось:

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

export default DS.Model.extend({
    createdAt: DS.attr("timestamp")
});

А потом в какой-то контроллер или что-то:

this.store.createRecord("somemodel", { createdAt: Firebase.ServerValue.TIMESTAMP });

Когда вы сохраните его, он установит поле с правильным значением на копии сервера, но локальная запись не будет обновлена ​​с этим значением. Я все еще работаю над тем, как это исправить, но новый метод Ember Data Store.fetch() кажется худшим решением, когда EmberFire обновлен.

редактировать:

Сделал еще несколько копаний. Некоторые заметки:

  • Когда вы создаете запись с помощью этого метода и вызываете для нее функцию save(), DS.Store вызывает обработчик события didCreateRecord, который обычно десериализует возвращаемую сервером запись (где вы обычно получаете идентификаторы моделей и прочее), но в этом случае он не десериализуется, потому что методы create/updateRecord FirebaseAdapter возвращают обещания, которые вызывают их обработчики разрешения без каких-либо аргументов ( https://github.com/firebase/emberfire/blob/v1.3.1/src/data.js#L492), поэтому метод Store становится неопределенным, а не сериализованной записью. С точки зрения прокладывания этого варианта использования, именно здесь я бы хотел найти решение, в идеале.

  • Похоже, серверное время генерируется как оценка, в любом случае синхронно на клиенте через переменную смещения времени, которая устанавливается при подключении веб-сокета сервера. Таким образом, когда вы сохраняете / обновляете запись со значением Firebase.ServerValues.TIMESTAMP, она отнимает у клиента время, изменяет его по смещению и создает с ним данные обновления. Похоже, что это будет изменено на фактическое значение на сервере, и модификация в конечном итоге распространится на клиента. - Если вам действительно нужно это значение немедленно, вы можете сохранить свою запись во второй раз, и она выдаст вам сгенерированное сервером значение.

По умолчанию date преобразование преобразует Firebase.ServerValue.TIMESTAMP в null потому что это не объект Date ( см. проверку трансформации здесь).

Вы можете создать собственное преобразование или переопределить код сериализации атрибута, чтобы передать константу Firebase без изменений. Я предпочитаю переопределять в сериализаторе, чтобы не требовалось никакого специального преобразования:

// app/serializers/application.js

import Firebase from 'firebase';
import FirebaseSerializer from 'emberfire/serializers/firebase';

export default FirebaseSerializer.extend({

  /**
   * Override the attribute serializer to pass through
   * Firebase.ServerValue.TIMESTAMP unaltered.
   *
   * @override
   */
  serializeAttribute(snapshot, json, key, attribute) {
    this._super(snapshot, json, key, attribute);

    var value = snapshot.attr(key);

    if (this._canSerialize(key)) {
      if (value === Firebase.ServerValue.TIMESTAMP) {
        var payloadKey = this._getMappedKey(key);
        if (payloadKey === key) {
          payloadKey = this.keyForAttribute(key, 'serialize');
        }

        // do not transform
        json[payloadKey] = value;
      }
    }
  }

});

Я включу это в базовый сериализатор emberfire.

Другие вопросы по тегам