Ember Data 1.0 Beta changed a lot for most of us … A topic I see often reappear on this forum and on Stackoverflow is the hasMany relationship. In this post I will give some additional information and code snippets that might help you.
Do not hesitate to provide feedback with your findings.
**1. Use the latest canary build and verify the serializeHasMany method **
Yes, you are working with bleeding edge technology. In Ember Data 1.0 Beta 1 and Beta 2, hasMany relationships do not work. The team is working hard and the latest canary build (dated sept 11) provides “almost” a solution. Open the canay build and verify that in the serializeHasMany method, the following is used in the if statement (thus 3 || statements):
if (relationshipType === 'manyToNone'
|| relationshipType === 'manyToMany'
|| relationshipType === 'manyToOne')
2. Defining the models
Identical to previous versions, the parent model should include a hasMany relationship. See code snippet below:
App.Post= DS.Model.extend({
title: DS.attr('string'),
body: DS.attr('string'),
publishedAt: DS.attr('date'),
comments: DS.hasMany('comment')
});
App.Comment = DS.Model.extend({
commenttext: DS.attr('string')
});
3. Adding a child record to the parent
You will probably implement this in a controller; in my case, I called the controller CommentNewcontroller. The proces to add a child to a parent is as follows:
- Create a child record
- Save the child record
- If the save is succesful, you will receive an id for the child
- Add the child to the parent
- Save the parent
Below is my code snippet (some rough error handling is added, but should be further detailed):
App.CommentNewController = Em.ObjectController.extend({
needs: ['postsShow'],
commenttext: null,
actions:{
addComment: function (body) {
this.set('commenttext', null);
},
save: function () {
//Create a new comment record
var comment = this.store.createRecord('comment', {
commenttext: this.get('commenttext')
});
//The post to be updated
var post = this.get('controllers.postsShow.content');
//Save the comment and then the post
comment.save().then(
function () {
//Succesful save of comment; thus add to post
post.get('comments').addObject(comment);
//Save post
post.save().then(
function () {
//Succesful save of post
},
function (error) {
console.log("API error occured - " + error.responseText);
alert("An error occured - REST API not available - Please try again");
}
);
},
function (error) {
console.log("API Error occured - " + error.responseText);
alert("An error occured - REST API not available - Please try again");
}
);
}
}
});
Please make sure to use Ember Inspector when testing your “save” code; at any time, the models at client side should be in sync with the server !
REST API call when saving the child (in this case a comment):
POST Request:
{
comment:{
commenttext:Comment 123
}
}
Expected Response:
{
"comment": {
"commenttext": "Comment 123",
"id": "52306b97d8861e281400001a"
}
}
REST API call when saving the parent (in this case a post):
PUT Request:
{post:{
title: "Post 123"
body: "<p>POST 123</p>"
comments: [0: "52306b97d8861e281400001a"]
}}
Expected Response:
{
"post": {
"title": "Post 123",
"body": "<p>POST 123</p>",
"comments": [
"52306b97d8861e281400001a"
],
"id": "52306b8cd8861e2814000019"
}
}
4. Reading (getting a parent and the childs)
When getting a post record, the child records should be referenced, but not embedded in the parent. Embedded childs are at this moment not supported. You should also make sure that your REST API has an interface to get the child records in batch (thus get multiple childs in one call). Ember Data will automatically fetch the child records via a seperate API call.
When loading a post with 2 comments, the API calls are as follows:
Get the post:
http://localhost:3000/posts/52306b8cd8861e2814000019
Expected response:
{
"post": {
"id": "52306b8cd8861e2814000019",
"title": "Post 123",
"body": "<p>POST 123</p>",
"comments": [
"52306b97d8861e281400001a",
"52306e8dd8861e281400001b"
]
}
}
Get the child records:
http://localhost:3000/comments?ids[]=52306b97d8861e281400001a&ids[]=52306e8dd8861e281400001b
Hope this article can take away some of the confusion with Ember Data and the hasMany relationships …
Marc