Series: Introduction to Ember Data 2.0

Ember Data 2.0-Relationships

Published on Dec 30, 2015

One amazing ability of Ember Data is connecting your models together through relationships in such a way that you don’t have to know the nitty-gritty details.

In this episode we look at the hasMany and belongsTo methods, seeing how they can be combined and how to use their async, inverse, and defaultValue options.


Links

Code

You can define relationships by calling DS.belongsTo or DS.hasMany or a DS.Model. The first argument is a string giving the name of the model used in the relationship.

export default DS.Model.extend({
    user: DS.belongsTo('user')
})

Ember Data can infer the model without the first argument if the property name matches to the class name:

export default DS.Model.extend({
    monster: DS.belongsTo(), //infers 'monster'
    teamMemberships: DS.hasMany(), //infers 'team-membership'
    favoriteMonster: DS.belongsTo('monster') //requires specification
})

The second argument to both of these methods is a hash with three possible properties: async, inverse, and defaultValue. They are all demonstrated in the following reflexive relationship:

export default DS.Model.extend({
    parent: DS.belongsTo('state', {inverse: 'children', async: true}),
    children: DS.hasMany('state', {defaultValue: [], inverse: 'parent', async: true})
})

Transcript

One of the really cool things about Ember Data is how it lets you connect your models with relationships. In this episode, we’ll go over the belongsTo and hasMany relationships.

So in your models, your DS models, you can define relationships just like you can attributes. So here, we’re defining the hasMany relationship of team-membership to the teamMemberships property.

Then, in the team-membership model, we’re having the monster property belonging to the monster model. And so, it’s going to be linking to one monster model, and it will also be linking to one user. And then in the user model, it’s going to be linking to many teamMemberships.

Now what this lets you do is it lets you have these relationships without worrying a whole lot about the underlying how Ember Data is fetching it from the server. It lets you act almost as if the stuff is already there.

And then here you can like alright, let’s get the currentUser, let’s get all the teamMemberships on it, and you don’t have to worry as much about the underlying structure. I mean you do a little bit, because as you can see in this example, we’re checking to see if the memberships have already landed before we do the mapBy. But if we reference these relationships in a template, then Ember would take care of that for us.

It’s worth noting that if the model names correspond to the property names, then you don’t actually have to state the model name as an argument. You can just leave it blank. However, if the model name doesn’t correspond with the property name, you do need to have the model name as the first argument.

For example if we had favoriteMonster on the user, then it would be a belongsTo, and we would have to specify that it’s a monster, since there’s no favoriteMonster model.

There’s also some terminology that you should know that people use when talking about relationships. So here we have a team member relationship and we have many team members. And in team members well the team-membership belongs to one user. We call that a one-to-many relationship. You can also have a one-to-one relationship by having two models that have two belongs-to relationships that connect. And you can also have a many-to-many relationship by having two models that have hasMany relationships that connect.

So for both belongsTo and hasMany, there are two optional arguments that you can put into the second parameter. So first you have the name then you have the optional arguments. The first optional argument is async, and that lets Ember Data know whether this relationship is going to be synchronous or asynchronous.

Now it was false by default before Ember Data 2.0, but now in Ember Data 2.0, it’s true by default, and you have to manually turn it off if you want it to be purely synchronous. And in general, you’re going to want it to be async.

Let me show you what synchronous versus asynchronous means. But before we do that, we’ll have to get into looking at this payload. So this is using the active model adapter, but the general lesson that I’m going to show you should carry over.

So here in this monsters call, it gives us both monsters and team_memberships . And here in the monsters, in the team_membership_ids property, it gives us an array of team membership ids. And for this, this could be both synchronous and asynchronous, because we’re including the team_memberships.

However, with the team_memberships, notice we have the monster _id and the user_id. These are both asynchronous by default, but it would be okay for the monster to be synchronous because this monster is included. But if we had the user as synchronous, then that would cause a problem because we haven’t included any users in this payload. So if it’s synchronous, it has to be included in the payload. If it’s asynchronous, then it can be fetched whenever you need it, not necessarily in the same payload.

So that’s the async option. Now let’s talk about the inverse option. So the inverse option is useful if you have two models that have multiple types of relationships to each other. So the example they give in the documentation is that in the comments... a comment can have different relationships to different posts. And then the post, it wants all the comments of a certain type, so it only wants the comments where this post is their redPost. This example is a little bit nonsensical, but hopefully you can get the idea.

Let’s look at a possibly more useful example from our model state explorer. So here on our state model, we have the parent relationship and the children relationship. So the parent, it belongsTo another state, and the inverse is children. And for the children, it hasMany states and the inverse is parent. So it’s not just one model related to another model, it’s one model related to itself. So this helps us keep track of how they’re related.

Now notice that we also have a third thing that wasn’t in the documentation, defaultValue. And that’ll just set what it is before you get anything back, or if it’s null.

So that’s our exploration of the belongsTo and hasMany methods, the relationships in Ember Data. In this week’s pro-episode, we’ll be going over more of this code that I used to create the model state demonstration. It was introduced a couple of episodes back and now I’m going to show you some of the cool things I did while making it. I hope to see you then.

Introduction to Ember Data 2.0

Subscribe to our mailing list