Skip to content

Instantly share code, notes, and snippets.

@amk221
Last active November 17, 2015 14:10
Show Gist options
  • Save amk221/0dfc8aa40f2d95abdc96 to your computer and use it in GitHub Desktop.
Save amk221/0dfc8aa40f2d95abdc96 to your computer and use it in GitHub Desktop.
Fix for Ember Data creating duplicate records
import { test, moduleForModel } from 'ember-qunit';
import Model from 'ember-data/model';
import BaseModel from 'capsule/pods/base/model';
import attr from 'ember-data/attr';
import run from 'ember-runloop';
import DS from 'ember-data';
import Pretender from 'pretender';
import RESTSerializer from 'ember-data/serializers/rest';
import { hasMany, belongsTo } from 'ember-data/relationships';
moduleForModel('base');
test('#save (fix for duplicate embedded records)', function(assert) {
assert.expect(12);
let foo, bar1, bar2, baz1;
let store = this.store();
let payload = {
foo: {
id: 1,
name: 'foo 1 (saved)',
bars: [
{ id: 1, name: 'bar 1 (saved)' },
{ id: 2, name: 'bar 2 (saved)' }
],
baz: {
id: 1,
name: 'baz 1 (saved)'
}
}
};
let server = new Pretender(function() {
this.post('/foos', () => [200, {}, payload]);
});
let FooSerializer = RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
bars: {
embedded: 'always'
},
baz: {
embedded: 'always'
}
}
});
this.registry.register('serializer:foo', FooSerializer);
this.registry.register('serializer:bar', RESTSerializer);
this.registry.register('serializer:baz', RESTSerializer);
this.registry.register('model:bar', Model.extend({ name: attr('string') }));
this.registry.register('model:baz', Model.extend({ name: attr('string') }));
this.registry.register('model:foo', BaseModel.extend({
name: attr('string'),
bars: hasMany('bar', { async: false }),
baz: belongsTo('baz', { async: false })
}));
run(function() {
foo = store.createRecord('foo', { name: 'foo 1' });
bar1 = store.createRecord('bar', { name: 'bar 1' });
bar2 = store.createRecord('bar', { name: 'bar 2' });
baz1 = store.createRecord('baz', { name: 'baz 1' });
foo.get('bars').pushObject(bar1);
foo.get('bars').pushObject(bar2);
foo.set('baz', baz1);
});
run(function() {
assert.equal(foo.get('name'), 'foo 1');
assert.equal(foo.get('bars').objectAt(0).get('name'), 'bar 1');
assert.equal(foo.get('bars').objectAt(1).get('name'), 'bar 2');
assert.equal(foo.get('baz.name'), 'baz 1');
assert.equal(store.peekAll('bar').get('length'), 2);
assert.equal(store.peekAll('baz').get('length'), 1);
foo.save().then(function() {
assert.equal(foo.get('name'), 'foo 1 (saved)');
assert.equal(foo.get('bars').objectAt(0).get('name'), 'bar 1 (saved)');
assert.equal(foo.get('bars').objectAt(1).get('name'), 'bar 2 (saved)');
assert.equal(foo.get('baz.name'), 'baz 1 (saved)');
assert.equal(store.peekAll('bar').get('length'), 2);
assert.equal(store.peekAll('baz').get('length'), 1);
});
});
server.shutdown();
});
import Model from 'ember-data/model';
import run from 'ember-runloop';
const { keys } = Object;
export default Model.extend({
save(...args) {
let dupeRecords = [];
let addDupe = (record) => {
if (record && record.get('isNew')) {
dupeRecords.push(record);
}
};
let implicitFix = (record) => {
let rels = record._internalModel._implicitRelationships;
keys(rels).forEach(name => delete rels[name]);
};
let deleteDupe = (record) => {
run(() => {
implicitFix(record);
record.deleteRecord();
});
};
this.eachRelationship((name, descriptor) => {
if (descriptor.options.async) {
return;
}
if (descriptor.kind === 'hasMany') {
this.get(name).forEach(addDupe);
} else if (descriptor.kind === 'belongsTo') {
addDupe(this.get(name));
}
});
return this._super(...args).then(() => {
dupeRecords.forEach(deleteDupe);
});
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment