Skip to content
Open
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