Why the createdAt will become null when i update the data?

I currently facing this issues when i need to perform update detail. The createdAt will get the current timestamp when a post is created. When i perform edit the post, the createdAt timestamp will become null. I found out that it need to refresh the page after create a post, then the createdAt timestamp will not become null when perform edit. Is the edit function only able to update data attribute but not the timestamp?

Post model:

    title: DS.attr('string'),
    description: DS.attr('string'),
    createdAt: DS.attr('date', {
        defaultValue() { return new Date();}

Edit function:

savePost(editedTitle, editedDescription, postId) {
            this.store.findRecord('post', postId).then((post) => {
                post.set("title", editedTitle);
                post.set("description", editedDescription);

what does the server responses for both cases? (when you do the refresh vs when you don’t?)

Also a suggestion, which might actually be the source of the issue, if the post you are editing is guaranteed to be in the store already, you can use peekRecord instead of findRecord like this:

  let post = this.store.peekRecord('post', postId);
  post.set("title", editedTitle);
  post.set("description", editedDescription);

This will prevent all the async behavior associated with findRecord (including a background refresh, which could be messing with the timestamp)

1 Like

When i do the refresh after posting a data, perform edit function will not messing the timestamp. But if i don’t do a refresh after posting a data, perform edit function will messing the timestamp and turn it to null value.

By the way, use peekRecord had solve the issue. But why a background refresh could be messing with the timestamp?

I think it can be very helpful to understand more of the nuance behind the ember data methods because they can cause some strange side effects as you just saw.

The findRecord method, by default, is actually probably better described like “peek and refresh OR fetch record”. Essentially what it does is peekRecord(type, id) to see if the record is already in the store (I doubt it actually uses peekRecord behind the scenes but that’s basically what it does), then:

  1. if the record is already in the store, it will resolve the promise immediately with the store record, but then it will do a background refresh of the record
  2. if the record is not already in the store it will fetch it and not resolve until it has the record

So in scenario 1 above what you’ll often see is a model hook or findRecord(...).then will resolve but then a second or two later the record will update again with the changes from the refresh. This can lead to unexpected visual flickers or, in a case like yours, data overwrites (if the server doesn’t have a createdAt timestamp it could overwrite the local record’s timestamp value with null/undefined).

The background refresh can be turned off globally or on a per-call basis with { backgroundReload: false }. This is more like “peek or fetch record”

So it pays to be very intentional about which methods you choose and the options you use for them. A few rules of thumb:

  • if you’re fetching a record that you know will be in the store, use peekRecord(type, id)
  • if you’re fetching a record that won’t necessarily be in the store (let’s say an edit route, you could get there from a list but also from a refresh), but you don’t want background refresh, use store.findRecord(type, id, { backgroundReload: false })
  • if you’re fetching a record that either definitely won’t be in the store or you want to refresh, just use regular old findRecord(type, id)

Another thing you can check out: Sam and Ryan, the good folks over at EmberMap, created an addon called ember-data-storefront which solves some of the ergonomic issues (like this one) that are common with Ember Data methods. The idea is to have store method analogs that behave more intuitively and require less boilerplate to work around stuff like the background refresh lag, etc. Definitely worth a look.