In a previous post I explained the basics of SANE and created a simple application. In this post I'll be going one step further and adding a relationship between two tables, using Sails.js, Mongo and Ember.
Relatonships occur when one foreign key references the primary key of another. Since we'll be using a nosql data store we'll be using document references instead. We'll set the schema using Sails.js so don't worry too much about that for now.
Getting Started In Sails.js
First things first we'll create the structure for the application using SANE. Check out the Sanestack.com if you need help installing it.
$ sane new OneToMany -d mongo
As always we'll check to see if everything runs.
$ cd OneToMany
$ sane up
If everything runs without error continue on. If you run into any error let me know in the comments and I can see if I can help.
Now we need to create a post and a comment resource.
$ sane generate resource post name:string date:string creator:string content:string
$ sane generate resource comment content:string date:string creator:string
Each post will have zero or more comments. Each comment will only have one post. This will be the simple relationship we use in this example. The sane generate command will add the model to both Ember and Sails.js
We can check to make sure everything is working on our server by visiting http://localhost:1337/api/v1/comments and http://localhost:1337/api/v1/posts. As long as our server is up it should return an empty array.
To be able to recognize the relationship we need to setup the Sails model. We already generated the schema, now we just need to add one more thing.
// server/api/models/Post.js
module.exports = {
attributes: {
//reltionship
comments: {
collection: 'comment',
via: 'poster'
},
name : { type: 'string' },
date : { type: 'string' },
creator : { type: 'string' },
content : { type: 'string' }
}
};
We added a new relationship at the top called comments. This simply tells Sails that we have zero, one or many comments associated via the comment collection.
// server/api/models/Comment.js
module.exports = {
attributes: {
poster: {
model:'post'
},
content : { type: 'string' },
date : { type: 'string' },
creator : { type: 'string' }
}
};
The Comment.js file tells Sails that every comment has one, or zero posts. This is very important not to skip this step or your association won't work.
Once again we'll use Postmanto send a few comments and posts to our server.
We'll begin by creating a post. It should look something like this.
After you send this POST message go back to your web browser and check to make sure it was created at http://localhost:1337/api/v1/posts. You should see something like this.
{
"posts": [
{
"comments": [
],
"name": "test",
"date": "3/25/14",
"creator": "bsmith",
"content": "this is a test",
"createdAt": "2015-04-28T05:43:16.796Z",
"updatedAt": "2015-04-28T05:43:16.796Z",
"id": "553f1df47aaa65a252dbe994"
},
]
}
Grab the id that you see listed. Now add a comment and reference that id. To add a comment in Postman send a message to your server like this.
The poster field is the id of the post you just created earlier. That should link up everything up so next time you bring up the server you'll see the comment ids in your post. Go ahead and create a few comments. In a future date I'll explain how to do this via Ember.
The response from the server should look something like this if everything is working OK.
// http://localhost:1337/posts
{
"posts": [
{
"comments": [
"553f1f2f7aaa65a252dbe997",
"553f22bd05e880835372804a"
],
"name": "test",
"date": "3/25/14",
"creator": "bsmith",
"content": "this is a test",
"createdAt": "2015-04-28T05:43:16.796Z",
"updatedAt": "2015-04-28T05:43:16.796Z",
"id": "553f1df47aaa65a252dbe994"
}
]
}
Next we'll setup Ember!
Ember Setup
First we'll go into our route and make sure it returns all the posts.
// client/app/routes/post.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function (){
return this.store.find('post');
}
});
Then we need to set the association in the Ember model so it correctly displays our data.
// client/app/models/post.js
import DS from 'ember-data';
export default DS.Model.extend({
comments: DS.hasMany('comment', {async: true}),
name: DS.attr('string'),
date: DS.attr('string'),
creator: DS.attr('string'),
content: DS.attr('string')
});
The name,date,creator and content should already be there since the sane-cli has already generated it. The hasMany tells Ember that we have an array of comments associated.
// client/app/models/comment.js
import DS from 'ember-data';
export default DS.Model.extend({
poster: DS.belongsTo('post', {async: true}),
content: DS.attr('string'),
date: DS.attr('string'),
creator: DS.attr('string')
});
The belongsTo tells Ember that comments belong to only one post. You can learn more about Ember and relationships here.
Finally we need to add a simple template just to loop over all the posts and display all the comments with each one. For the sake of simplicity I'm not going to add any special css or HTML to make this look nice.
// client/app/templates/post.hbs
This is all the posts<br>
{{#each model as |posts|}}
Name: {{posts.name}}<br>
Date: {{posts.date}}<br>
Author: {{posts.creator}}<br>
Content: {{posts.content}}<br>
<br>
Comments: <br><br>
{{#each posts.comments as |comments|}}
{{comments.content}}<br>
{{comments.creator}}<br>
{{comments.date}}<br>
<br>
{{/each}}
{{/each}}
The each loops over the model that we setup in the route. The model we setup for post has comments which is also an array. To display comments we can simply have another each block that loops over them.
If all is well you should see a screen like this when you navigate to http://localhost:4200/post
Future
There is a lot more we could do here. We could create a simple way of adding new comments and posts or we could look into other relationships like many-to-many. This is just the beginning. I'll save those for future posts.
Have a question? Leave a comment below.
Image Credit StrategyDriven.com