I have a problem similar to this stack overflow question, except the answer doesn't seem to be working. I have a form in which the user creates a container module with a variable number of submodels. When the form is submitted, I have to save the container, the submodels, and make sure that the the hasMany relationship persists. My code (using Ember-Cli):
container:
var Container= DS.Model.extend({
name: DS.attr('string'),
submodels: DS.hasMany('submodel'),
lastModified: DS.attr('date')
});
export default Container;
submodel:
var Submodel= DS.Model.extend({
char: DS.belongsTo('container'),
name: DS.attr('string'),
desc: DS.attr('string'),
priority: DS.attr('number'),
effort: DS.attr('number'),
time: DS.attr('number')
});
export default Submodel;
ContainersNewRoute:
export default Ember.Route.extend({
model: function() {
return this.store.createRecord('container', {
...
});
}
});
ContainersNewController:
export default Ember.ObjectController.extend({
actions: {
addSubmodel: function() {
var submodels= this.get('model.submodels');
submodels.addObject(this.store.createRecord('submodel', {
...
}));
},
saveNewContainer: function () {
var container = this.get('model');
container.save().then(function(){
var promises = Ember.A();
container.get('submodels').forEach(function(item){
promises.push(item.save);
console.log(item);
});
Ember.RSVP.Promise.all(promises).then(function(resolvedPromises){
alert('all saved');
});
});
this.transitionToRoute(...);
}
}
});
The Ember Data itself works fine, transition to a view of the created container, with submodels listed. Refresh the page, and the submodels disappear from the container view.
I've tried a few variations, for example using pushObject rather than the addObject from the stack overflow answer. I've also tried using the Ember.RSVP callback to run container.save() a second time after the submodels have been saved.
After some further testing, I've found that the submodels are not persisting at all.
Is there a sane way to save 1) the container 2) the submodels 3) the hasMany/belongsTo relationships to each other?
Or does this some how need to be broken down into discrete steps where I save the container, save the submodels, the push the submodels to the container to get the hasMany relationship and resave the container, and lastly make the submodels belongTo the container and save the submodels again?
By default, DS.hasMany
on a one to many association won't include ids
field when serializing. You can use DS.EmbeddedRecordsMixin
to change this behavior.
Please read Embedded Records Mixin section on A Thorough Guide to Ember Data for more. (disclaimer, I'm its author.)
DS.EmbeddedRecordsMixin
is an extension for DS.ActiveModelSerializer
which allows configuring of how associations get serialized or deserialized. Although not yet complete (especially with regard to polymorphic associations), it is intriguing nonetheless.
You can choose:
Code Sample:
App.CartSerializer = DS.ActiveModelSerializer
.extend(DS.EmbeddedRecordsMixin)
.extend{
attrs: {
items: {serialize: 'ids', deserialize: 'ids'}
}
});
App.Cart = DS.Model.extend({
items: DS.hasMany('item', {async: true})
});
App.Item = DS.Model.extend({
cart: DS.belongsTo('item', {async: true})
});
You have the problem that I've experienced earlier, you have easier example than my cause you need only one relation :hasMany and :belongsTo
Try to use this approach:
export default Ember.ObjectController.extend({
// here we can pre-load submodels container,
//even if it's empty because 'this.get('model.submodels')' returns promise
submodels: function () {
return this.get('model.submodels');
}.property('[email protected]'),
actions: {
addSubmodel: function () {
//saving context of controller, saving container for
//better understanding (clear vision)
var controller = this,
container = controller.get('conrtainer');
//container instead of 'model' for better understanding :)
//1. Creating submodel
var submodel = this.get('store').createRecord('submodel', {
// ... //
container: container
});
//2. Saving submodel
submodel.save().then(function (submodel_res) {
//3. It isn't the end though :)
//Now we're getting our submodels from the container - here we will get
//the result instead of promise, remember we pre-loaded it :) -1 nesting lvl
controller.get("submodels").pushObject(submodel_res);
//4. Now we need to update our 'parent' model - Container
container.save().then(function (post_res) {
console.log(post_res); // 5. Doesn't matter we are happy
}, function (err) {
console.log(err);
});
}, function (err) {
console.log(err);
});
}
}
});
//In order to use this approach you need to override property
//in model serializer (just copy it and //paste :) )
YourApp.ContainerSerializer = DS.ActiveModelSerializer.extend({
// here coulbe be RESTSerializer as well ;)
primaryKey: function () {
return '_id';
}.property(),
// it's just helpful tip, if you use mongo like me ;)
//it doesn't relates to the main topic itself
// this little method will help you update 'parent' model ;)
serializeHasMany: function (record, json, relationship) {
var key = relationship.key;
var json_key = key.singularize().decamelize() + '_ids';
var relationshipType = DS.RelationshipChange.determineRelationshipType(
record.constructor, relationship);
if (relationshipType === 'manyToNone'
|| relationshipType === 'manyToMany'
|| relationshipType === 'manyToOne') {
json[json_key] = Ember.get(record, key).mapBy('id');
}
}
});
Good luck ;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With