Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix record create/save on FixtureAdapter so revert works #368

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions packages/ember-model/lib/belongs_to.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ Ember.belongsTo = function(type, options) {

var dirtyChanged = function(sender) {
if (sender.get('isDirty')) {
self._relationshipBecameDirty(key);
self._relationshipBecameDirty(propertyKey);
} else {
self._relationshipBecameClean(key);
self._relationshipBecameClean(propertyKey);
}
};

Expand Down
30 changes: 27 additions & 3 deletions packages/ember-model/lib/fixture_adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,29 +80,53 @@ Ember.FixtureAdapter = Ember.Adapter.extend({

return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.run.later(this, function() {
var data;

self._setPrimaryKey(record);
fixtures.push(klass.findFromCacheOrLoad(record.toJSON()));
record.didCreateRecord();
data = record.toJSON();
fixtures.push(klass.findFromCacheOrLoad(data));
self.didCreateRecord(record, data);
resolve(record);
}, 0);
});
},

didCreateRecord: function(record, data) {
this._loadRecordFromData(record, data);
record.didCreateRecord();
},

saveRecord: function(record) {
var self = this, data = record.toJSON();

return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.run.later(this, function() {
record.didSaveRecord();
self.didSaveRecord(record, data);
resolve(record);
}, 0);
});
},

didSaveRecord: function(record, data) {
this._loadRecordFromData(record, data);
record.didSaveRecord();
},

deleteRecord: function(record) {
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.run.later(this, function() {
record.didDeleteRecord();
resolve(record);
}, 0);
});
},

_loadRecordFromData: function(record, data) {
var rootKey = get(record.constructor, 'rootKey'),
primaryKey = get(record.constructor, 'primaryKey'),
dataToLoad = rootKey ? get(data, rootKey) : data;
if (!Ember.isEmpty(dataToLoad)) {
record.load(dataToLoad[primaryKey], dataToLoad);
}
}
});
15 changes: 7 additions & 8 deletions packages/ember-model/lib/has_many_array.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,16 +168,15 @@ Ember.HasManyArray = Ember.ManyArray.extend({
var klass = get(this, 'modelClass'),
content = get(this, 'content'),
reference = content.objectAt(idx),
record;
record = reference.record;

if (reference.record) {
record = reference.record;
} else {
record = klass.find(reference.id);
if (record) {
if (! record.container) {
record.container = container;
}
return record;
}

record.container = container;
return record;
return klass._findFetchById(reference.id, false, container);
},

toJSON: function() {
Expand Down
26 changes: 19 additions & 7 deletions packages/ember-model/lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Ember.Model = Ember.Object.extend(Ember.Evented, {

if (!reference) {
reference = this.constructor._getOrCreateReferenceForId(id);
reference.record = this;
set(reference, 'record', this);
this._reference = reference;
} else if (reference.id !== id) {
reference.id = id;
Expand Down Expand Up @@ -165,7 +165,7 @@ Ember.Model = Ember.Object.extend(Ember.Evented, {
var record = this.get(key);
return record ? record.toJSON() : null;
} else {
var primaryKey = get(meta.getType(), 'primaryKey');
var primaryKey = get(meta.getType(this), 'primaryKey');
return this.get(key + '.' + primaryKey);
}
},
Expand All @@ -176,10 +176,16 @@ Ember.Model = Ember.Object.extend(Ember.Evented, {
attributes = this.constructor.getAttributes(),
relationships = this.constructor.getRelationships(),
properties = attributes ? this.getProperties(attributes) : {},
rootKey = get(this.constructor, 'rootKey');
rootKey = get(this.constructor, 'rootKey'),
isNew = get(this, 'isNew');

for (key in properties) {
meta = this.constructor.metaForProperty(key);
if (meta.options) {
if (meta.options.save === false || (meta.options.update === false && ! isNew)) {
continue;
}
}
if (meta.type && meta.type.serialize) {
json[this.dataKey(key)] = meta.type.serialize(properties[key]);
} else if (meta.type && Ember.Model.dataTypes[meta.type]) {
Expand All @@ -195,6 +201,11 @@ Ember.Model = Ember.Object.extend(Ember.Evented, {
for(var i = 0; i < relationships.length; i++) {
key = relationships[i];
meta = this.constructor.metaForProperty(key);
if (meta.options) {
if (meta.options.save === false || (meta.options.update === false && ! isNew)) {
continue;
}
}
relationshipKey = meta.options.key || key;

if (meta.kind === 'belongsTo') {
Expand Down Expand Up @@ -251,7 +262,6 @@ Ember.Model = Ember.Object.extend(Ember.Evented, {

set(this, 'isNew', false);

set(this, '_dirtyAttributes', []);
this.constructor.addToRecordArrays(this);
this.trigger('didCreateRecord');
this.didSaveRecord();
Expand Down Expand Up @@ -650,7 +660,9 @@ Ember.Model.reopenClass({
getCachedReferenceRecord: function(id, container){
var ref = this._getReferenceById(id);
if(ref && ref.record) {
ref.record.container = container;
if (! ref.record.container) {
ref.record.container = container;
}
return ref.record;
}
return undefined;
Expand Down Expand Up @@ -770,15 +782,15 @@ Ember.Model.reopenClass({
}, this).forEach(callback);
},

load: function(hashes) {
load: function(hashes, container) {
if (Ember.typeOf(hashes) !== 'array') { hashes = [hashes]; }

if (!this.sideloadedData) { this.sideloadedData = {}; }

for (var i = 0, l = hashes.length; i < l; i++) {
var hash = hashes[i],
primaryKey = hash[get(this, 'primaryKey')],
record = this.getCachedReferenceRecord(primaryKey);
record = this.getCachedReferenceRecord(primaryKey, container);

if (record) {
record.load(primaryKey, hash);
Expand Down
22 changes: 16 additions & 6 deletions packages/ember-model/lib/store.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
function NIL() {}

Ember.Model.Store = Ember.Object.extend({
container: null,
Expand All @@ -22,14 +21,24 @@ Ember.Model.Store = Ember.Object.extend({
}
},

createRecord: function(type) {
modelWithAdapterFor: function(type) {
var klass = this.modelFor(type);
klass.reopenClass({adapter: this.adapterFor(type)});
return klass.create({container: this.container});
if (! klass.adapter) {
klass.reopenClass({adapter: this.adapterFor(type)});
}
return klass;
},

createRecord: function(type, props) {
var klass = this.modelFor(type);
if (! klass.adapter) {
klass.reopenClass({adapter: this.adapterFor(type)});
}
return klass.create(Ember.merge({container: this.container}, props));
},

find: function(type, id) {
if (arguments.length === 1) { id = NIL; }
if (arguments.length === 1) { id = undefined; }
return this._find(type, id, true);
},

Expand All @@ -40,7 +49,7 @@ Ember.Model.Store = Ember.Object.extend({
klass.reopenClass({adapter: this.adapterFor(type)});
// }

if (id === NIL) {
if (id === undefined) {
return klass._findFetchAll(async, this.container);
} else if (Ember.isArray(id)) {
return klass._findFetchMany(id, async, this.container);
Expand All @@ -52,6 +61,7 @@ Ember.Model.Store = Ember.Object.extend({
},

_findSync: function(type, id) {
if (arguments.length === 1) { id = undefined; }
return this._find(type, id, false);
}
});
Expand Down
31 changes: 28 additions & 3 deletions packages/ember-model/tests/adapter/fixture_adapter_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,35 @@ test("createRecord", function() {
stop();
});

test("revert", function() {
expect(6);

FixtureModel.FIXTURES = [];

var record = FixtureModel.create({name: "Erik"});

// Ember.run(record, record.save);
Ember.run(record, record.save).then(function(record) {
start();
// test revert of a clean record
record.revert();
equal(record.get('isDirty'), false, "Reverted clean record should not be dirty");
equal(record.get('id'), "fixture-0", "Value of clean Record #id should not have changed");
equal(record.get('name'), "Erik", "Value of clean Record #name should not have changed");
// test revert of a dirty model
record.set('name', 'Peter');
record.revert();
equal(record.get('isDirty'), false, "Reverted dirty record should not be dirty");
equal(record.get('id'), "fixture-0", "Value of dirty Record #id should not have changed");
equal(record.get('name'), "Erik", "Value of dirty Record #name should have reverted");
});
stop();
});

test("_generatePrimaryKey", function() {
expect(3);

equal(adapter._generatePrimaryKey(), "fixture-0", "Retrun next primary key");
equal(adapter._generatePrimaryKey(), "fixture-1", "Retrun next primary key");
equal(adapter._generatePrimaryKey(), "fixture-2", "Retrun next primary key");
equal(adapter._generatePrimaryKey(), "fixture-0", "Return next primary key");
equal(adapter._generatePrimaryKey(), "fixture-1", "Return next primary key");
equal(adapter._generatePrimaryKey(), "fixture-2", "Return next primary key");
});
86 changes: 86 additions & 0 deletions packages/ember-model/tests/dirty_tracking_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,51 @@ test("save parent of embedded belongsTo", function() {
});
});

test("save parent of embedded belongsTo with different named key", function() {
expect(9);
var json = {
id: 1,
name: 'foo',
the_author: { id: 1, name: 'Cory Loken' }
};

var Author = Ember.Model.extend({
id: Ember.attr(),
name: Ember.attr()
}),
Post = Ember.Model.extend({
id: Ember.attr(),
author: Ember.belongsTo(Author, {key: 'the_author', embedded: true})
});

Post.adapter = Ember.FixtureAdapter.create();

var post = Post.create();
Ember.run(post, post.load, json.id, json);
equal(post.get('isDirty'), false, 'post should be clean initially');

post.set('author.name', 'Billy Bob');
equal(post.get('author.isDirty'), true, 'author should be dirty after being modified');
equal(post.get('isDirty'), true, 'changes to embedded belongsTo should dirty the parent');

stop();
Ember.run(function() {
post.save().then(function() {
start();
equal(post.get('author.isDirty'), false, 'the author should be clean after being saved');
equal(post.get('isDirty'), false, 'the post should be clean after being saved');

post.set('author.name', 'John Doe');
equal(post.get('author.isDirty'), true, 'the author should be dirty again');
equal(post.get('isDirty'), true, 'the post should be dirty because the author is dirty');

post.set('author.name', 'Cory Loken'); // special case: setting back to its original value
equal(post.get('author.isDirty'), true, 'the author should be dirty because it was saved as "Billy Bob"');
equal(post.get('isDirty'), true, 'the post should be dirty because the author is dirty');
});
});
});

test("set embedded belongsTo", function() {
expect(9);
var json = {
Expand Down Expand Up @@ -701,3 +746,44 @@ test("manipulating the content of objects in a hasMany should dirty the parent",
ok(post.get('comments.isDirty') === true, "post.comments should be dirty after changing comment1's content");
ok(post.get('isDirty') === true, "Post should be dirty after changing comment1's content");
});

test("after saving new record, the model and it's embedded properties shouldn't be dirty", function() {
expect(5);

var Comment = Ember.Model.extend({
id: Ember.attr(),
name: Ember.attr()
});

var Post = Ember.Model.extend({
id: Ember.attr(),
comments: Ember.hasMany(Comment, {key: 'comments', embedded: true})
});

Post.adapter = {
createRecord: function(record) {
ok(true, "createRecord was called");
var deferred = Ember.Deferred.create();
deferred.then(function() {
record.didCreateRecord();
});
deferred.resolve(record);
return deferred;
}
};

var post = Post.create();
post.get('comments').create({name: 'Comment 1'});

ok(post.get('isDirty') === true, 'Post should be dirty initially');
ok(post.get('comments.isDirty') === true, 'Comments should be dirty initially');

stop();
Ember.run(function() {
post.save().then(function() {
start();
ok(!post.get('isDirty'), "Post should be clean");
ok(!post.get('comments.isDirty'), "Comments in post should be clean");
});
});
});
Loading