Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Give foreign key to child records, include in JSON

When adding a record to a hasMany association, we
should update the inverse belongsTo relationship
on the child record. Additionally, calling
`toJSON` on the child should include the foreign
key in the hash.
  • Loading branch information...
commit 32d138a04b22ee6ae528ac87fe64ceb6a7a931bf 1 parent c033ecf
tomhuda authored
View
12 packages/ember-data/lib/system/model/associations.js
@@ -88,8 +88,16 @@ var hasAssociation = function(type, options, one) {
key = (options && options.key) ? options.key : key;
if (one) {
- id = findRecord(store, type, data, key, true);
- association = id ? store.find(type, id) : null;
+ if (arguments.length === 2) {
+ data.setAssociation(key, get(value, 'clientId'));
+ // put the client id in `key` in the data hash
+ return value;
+ } else {
+ id = findRecord(store, type, data, key, true);
+ association = id ? store.find(type, id) : null;
+
+ // if we have an association, store its client id in `key` in the data hash
+ }
} else {
ids = findRecord(store, type, data, key);
association = store.findMany(type, ids);
View
38 packages/ember-data/lib/system/model/model.js
@@ -11,12 +11,17 @@ var retrieveFromCurrentState = Ember.computed(function(key) {
var DataProxy = function(record) {
this.record = record;
this.unsavedData = {};
+ this.associations = {};
};
DataProxy.prototype = {
get: function(key) { return Ember.get(this, key); },
set: function(key, value) { return Ember.set(this, key, value); },
+ setAssociation: function(key, value) {
+ this.associations[key] = value;
+ },
+
savedData: function() {
var savedData = this._savedData;
if (savedData) { return savedData; }
@@ -34,9 +39,20 @@ DataProxy.prototype = {
unknownProperty: function(key) {
var unsavedData = this.unsavedData,
- savedData = this.savedData();
+ associations = this.associations,
+ savedData = this.savedData(),
+ store;
- var value = unsavedData[key];
+ var value = unsavedData[key], association;
+
+ // if this is a belongsTo association, this will
+ // be a clientId.
+ association = associations[key];
+
+ if (association !== undefined) {
+ store = get(this.record, 'store');
+ return store.clientIdToId[association];
+ }
if (savedData && value === undefined) {
value = savedData[key];
@@ -148,12 +164,10 @@ DS.Model = Ember.Object.extend({
associations.forEach(function(key, meta) {
if (options.associations && meta.kind === 'hasMany') {
var association = get(this, key),
- type = meta.type,
- typeMap = store.typeMapFor(type),
- clientIdToIdMap = typeMap.cidToId,
+ clientIdToIdMap = store.clientIdToId,
clientIds = get(association, 'content'),
records = [],
- clientId, id;
+ clientId, serverId;
if (meta.options.embedded) {
association.forEach(function(record) {
@@ -163,15 +177,21 @@ DS.Model = Ember.Object.extend({
for (var i=0, l=clientIds.length; i<l; i++) {
clientId = clientIds[i];
- id = clientIdToIdMap[clientId];
+ serverId = clientIdToIdMap[clientId];
- if (id !== undefined) {
- records.push(id);
+ if (serverId !== undefined) {
+ records.push(serverId);
}
}
}
result[key] = records;
+ } else if (meta.kind === 'belongsTo') {
+ id = data.get(key);
+
+ if (id) {
+ result[key] = id;
+ }
}
}, this);
View
36 packages/ember-data/lib/system/model_array/many_array.js
@@ -10,13 +10,39 @@ DS.ManyArray = DS.ModelArray.extend({
var parentRecord = get(this, 'parentRecord');
var pendingParent = parentRecord && !get(parentRecord, 'id');
- added = added.map(function(item) {
- ember_assert("You can only add items of " + (get(this, 'type') && get(this, 'type').toString()) + " to this association.", !get(this, 'type') || (get(this, 'type') === item.constructor));
+ added = added.map(function(record) {
+ ember_assert("You can only add records of " + (get(this, 'type') && get(this, 'type').toString()) + " to this association.", !get(this, 'type') || (get(this, 'type') === record.constructor));
- if (pendingParent) { item.send('waitingOn', parentRecord); }
- return item.get('clientId');
- });
+ if (pendingParent) {
+ record.send('waitingOn', parentRecord);
+ }
+
+ this.assignInverse(record, parentRecord);
+
+ return record.get('clientId');
+ }, this);
this._super(index, removed, added);
+ },
+
+ assignInverse: function(record, parentRecord) {
+ var associationMap = get(record.constructor, 'associations'),
+ possibleAssociations = associationMap.get(record.constructor),
+ possible, actual;
+
+ if (!possibleAssociations) { return; }
+
+ for (var i = 0, l = possibleAssociations.length; i < l; i++) {
+ possible = possibleAssociations[i];
+
+ if (possible.kind === 'belongsTo') {
+ actual = possible;
+ break;
+ }
+ }
+
+ if (actual) {
+ set(record, actual.name, parentRecord);
+ }
}
});
View
14 packages/ember-data/lib/system/store.js
@@ -68,9 +68,12 @@ DS.Store = Ember.Object.extend({
set(DS, 'defaultStore', this);
}
- set(this, 'typeMaps', {});
- set(this, 'recordCache', []);
- set(this, 'modelArraysByClientId', {});
+ // internal bookkeeping; not observable
+ this.typeMaps = {};
+ this.recordCache = [];
+ this.clientIdToId = {};
+ this.modelArraysByClientId = {};
+
set(this, 'defaultTransaction', this.transaction());
return this._super();
@@ -462,7 +465,7 @@ DS.Store = Ember.Object.extend({
id = hash[primaryKey];
typeMap.idToCid[id] = clientId;
- typeMap.cidToId[clientId] = id;
+ this.clientIdToId[clientId] = id;
} else {
recordData.commit();
}
@@ -627,7 +630,6 @@ DS.Store = Ember.Object.extend({
return (typeMaps[guidForType] =
{
idToCid: {},
- cidToId: {},
clientIds: [],
cidToHash: {},
modelArrays: []
@@ -728,7 +730,7 @@ DS.Store = Ember.Object.extend({
var typeMap = this.typeMapFor(type);
var idToClientIdMap = typeMap.idToCid,
- clientIdToIdMap = typeMap.cidToId,
+ clientIdToIdMap = this.clientIdToId,
clientIds = typeMap.clientIds,
dataCache = typeMap.cidToHash;
View
31 packages/ember-data/tests/integration/associations_test.js
@@ -14,7 +14,9 @@ module("Association/adapter integration test", {
Comment = DS.Model.extend();
Comment.reopen({
- comments: DS.hasMany(Comment)
+ body: DS.attr('string'),
+ comments: DS.hasMany(Comment),
+ comment: DS.belongsTo(Comment)
});
},
@@ -104,3 +106,30 @@ test("if a parent record and an uncommitted pending child belong to different tr
parentTransaction.commit();
});
});
+
+
+test("if a record is added to another record's hasMany association, it receives a foreign key associated with the new object", function() {
+ store.load(Comment, { id: 1, comments: [] });
+ store.load(Comment, { id: 2, comments: [] });
+
+ var parentRecord = store.find(Comment, 1);
+ var childRecord = store.find(Comment, 2);
+
+ get(parentRecord, 'comments').pushObject(childRecord);
+ equal(get(childRecord, 'comment'), parentRecord);
+
+ var json = childRecord.toJSON();
+
+ equal(json.comment, 1);
+});
+
+test("if a record has a foreign key when loaded, it is included in the toJSON output", function() {
+ store.load(Comment, { id: 1, comments: [2] });
+ store.load(Comment, { id: 2, comment: 1, comments: [] });
+
+ var childRecord = store.find(Comment, 2);
+
+ var json = childRecord.toJSON();
+
+ equal(json.comment, 1);
+});
Please sign in to comment.
Something went wrong with that request. Please try again.