Можно ли с помощью 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.