Skip to content

Instantly share code, notes, and snippets.

@GeoffreyBooth
Last active October 13, 2016 08:39
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save GeoffreyBooth/cc0e7db6696649435a2a to your computer and use it in GitHub Desktop.
Save GeoffreyBooth/cc0e7db6696649435a2a to your computer and use it in GitHub Desktop.
Ember.js rollback relationships, including deletions of child objects
# RollbackAttributes should also rollback relationships
# Based on http://stackoverflow.com/a/27184207/223225 and https://github.com/emberjs/rfcs/pull/21#issuecomment-135134132
DS.Model.reopen
rollbackAttributes: ->
@_super()
@rollbackRelationships()
cacheOriginalRelations: ->
# Save original relations values to @originalRelations
@set 'originalRelations', {}
# The values of those relations are intially null, even with async: false; so do findRecord to get the complete record
@store.findRecord(@constructor.modelName, @id).then (record) =>
record.eachRelationship (key, relationship) =>
if relationship.kind is 'belongsTo'
@set "originalRelations.#{key}", record.get(key)
if relationship.kind is 'hasMany'
@set "originalRelations.#{key}", record.get(key).toArray()
ready: ->
@cacheOriginalRelations()
onReloading: (->
unless @get('isReloading')
@cacheOriginalRelations()
).observes('isReloading')
rollbackRelationships: ->
return unless @originalRelations?
Object.keys(@originalRelations).forEach (key) =>
# For each relation, set the key to the original value (another record or array of records)
if Ember.isArray(@get(key)) # Careful, as Ember.typeOf for ArrayProxy is 'instance'
@originalRelations[key].invoke 'rollbackAttributes' # Important! Do this BEFORE setting the value, so undo any possible deletions
@get(key).setObjects @originalRelations[key]
if Ember.typeOf(@get(key)) is 'instance'
@originalRelations[key].rollbackAttributes() if @originalRelations[key].rollbackAttributes? # Important! Do this BEFORE setting the value, so undo any possible deletions
@set key, @originalRelations[key]
else if Ember.typeOf(@get(key)) is 'null'
@set key, @originalRelations[key]
isDeepDirty: ->
return if @_super('isDirty') or not @originalRelations?
Object.keys(@originalRelations).any (key) =>
if Ember.isArray(@get(key))
return if @get(key).anyBy('isDirty') or @get(key).get('length') isnt @originalRelations[key].length
dirty = no
@get(key).forEach (item, index) =>
if item.get('id') isnt @originalRelations[key][index].get('id')
dirty = yes
return dirty
@get(key).get('isDirty') or @get(key).get('id') isnt @originalRelations[key].get('id')
@remino
Copy link

remino commented Jan 31, 2016

Thanks for the code. It was working for the most part, but sadly, it makes each model unit test fail with the following:

Assertion Failed: `id` has to be non-empty string or number

@aalasolutions-zz
Copy link

I did just wrapped the code in line 14 to 20 in if @id

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment