Expected behaviour of rollback after save attempt returns 422? (Ember Data 1.0)

Persuant to my github issue what is the expected behaviour of a rollback after a previous save attempt returned a 422 error? I expected a reset to the last known valid state but got only the clearing of the isDirty flag with all properties remaining in their invalid state. Is anyone else seeing this behaviour?



1 Like

I have the same behaviour:

Rollback of data changes (without first trying to save the changes):

  • all data properties restored to previous version
  • all flags in correct state

Rollback of data changes after an attempt to save, but the save returned a 422 error:

  • none of the data properties is restored (fields remain in error state)
  • isError flag remains true

I think this is a use case that is not very well supported at this moment … Have also registered it at ember.js - Ember data 1.0.0: rollback after unsuccesfull save does not revert properties - Stack Overflow

I chatted with @wycats about this on IRC and it seems that the current behavior is intended. Rollback only reverts any uncommitted changes – which does not include invalid attributes after a save. I can see the appeal of this in some situations. You don’t necessarily want invalid values to “pop” back to their previously known state if you’re getting back validation errors.

Presumably, some sort of transaction would be more suited for the use case you’re talking about, but I didn’t get any answers about the intended plan for re-implementing transactions in Ember Data 1.0.0 and there doesn’t seem to be an alternative to .rollback() anywhere in the code right now.

In the mean time, I was able to return my model to the previously known valid, non-dirty, non-error state by issuing a second .save() after a second .set() that put the attributes back to their previous state. Not optimal but it works.

I can sort of see this, and I definitely don’t want it happening as soon as the server errors, but an explicit request to a model that isError to rollback in my mind should treat server marked invalid data exactly the same as any other local change, because assuming a server is king relationship (pretty common for CRUD) that’s essentially what it is, a local modification not yet persisted (successfully) to the actual “one source of truth”.

This is essentially the method I’m pursuing, but it feels pretty backwards.

Thanks for the clarification anyway. :smile:

I agree, but it doesn’t seem like an uncommon one.

I’m also investigating http://epf.io/ but the documentation is…minimal is perhaps kindest.

This is not the use case I refer to. I do not want to revert to initial values when the server returns an error. I do however want an “escape” path in such a situation. In my app this is implemented as a “cancel/revert” button. When the user clicks on this button I want that the origianl values are restored independent of the actions he did before (modified some fields, tried to save but server did return 422). It now looks that this is not possible or that I need to implement different code for rollback depending on the isError flag …

Can you provide a small code sample with the .set and .save. I am not familiar with .set … do not understand how a .set can set back old values …

Hope you can help. thx Marc

Right, the current rollback only allows for an escape path before save() is called.

In my case, I’m simply flipping a “published” boolean from true back to false, so it’s literally just:

model.set("published", false).save()

in the failure callback of the original save(). If you’re looking to reset all of the model’s attributes (or a larger subset), you’ll have to store them somewhere before the model becomes dirty.

It does seem silly to have to make a second server trip when we know from the 422 response that the model was not updated. Am I wrong in thinking this is one of the intended uses of transactions (if/when they are re-integrated into Ember Data 1.0.0+)?

Get the latest canary build and modify the code as suggested ember.js - Ember data: save loses belongsTo relationship - Stack Overflow


checkout the pull request https://github.com/emberjs/data/pull/1273

@amarpalsapure Amar, I am confused here. This post is about rollback of model changes after a unsuccesful save attempt … this has nothing to do with your change of the hasMany relationship. Or am I missing something ?

…think it was a mis-reply. @cyclomarc did you see the reply from @wycats in this thread: https://github.com/emberjs/data/issues/1245. @ptsd showed a good use case (though not the only one) for a more thorough rollback.

@amarpalsapure Thx - A more thorough rollback would indeed be appreciated.

I do not fully agree that this is a feature request and not a bug. The following is not a logic flow:

  1. Change a model property so that it will fail when saving (isDirty = true)
  2. Save (isDirty = true and isError becomes true because the server returns a 422)
  3. Click on “Revert changes” (thus do rollback) - the isDirty flag is set to false and isError remains true; but the model properties are not set back to their initial values
  4. Save again (with exactly the same data); the server thus fails again with a 422
  5. Now, rollback again: and now, the properties are set back to their initial value ! But the isError flag remains true.

This is thus in any case not a stable behavior …

For now I see 3 workarounds:

  1. Store each model twice (keep a sort of read-only copy) so that in case of a 422 error and requesting a “revert changes” you can always revert to the copy you stored.

  2. Include in the 422 error response the initial data and then set each model property to the values returned.

  3. When clicking “revert changes”, clear the model and fetch the data again from the server.

But to be honest, I would nobody recommend implementing one of these methods … this is just what a client-side rollback should cover. But I also agree, this is not first priority !

My bad, replied to wrong question.

I agree that we could use a “more thorough rollback”. It’s one of the things I will be working on soon after reviewing a number of open issues and posts on this forum.

Awesome, thanks @wycats!

I am also trying to build this functionality (rollback changes after a 422) into my app. I’m curious, does anyone have a reasonable workaround in the meantime?

is this a still valid behavior?

I haven’t used Ember Data in a while (just been using bare $.ajax calls) so I’m not sure if it’s changed since I wrote that post…

In case anyone is still interested. This is still the behavior in beta8.

My use case is:

  • make changes to record
  • try to save
  • fail due to business login
  • try to go back to pre-save values

My workaround right now is to manually change this values and force the record to a loaded.saved state based on this

My bad. For anyone who will read this.

I have actually find out that with Ember-data 1.0.beta8 when I try to save a record which is in state root.loaded.updated.uncommitted and it fails, on promise failure handler the model is still in the same state.

New data are stored in _inFlightAttributes object while, in _data object the original data are maintained.

A call to record.rollback() will in fact delete all data present in _inFlightAttributes and put the record in state root.loaded.saved

My error comes from a bad modification of the record attributes, which failed to put the record in root.loaded.updated.uncommitted state.