Defining Models Edit Page


A model is a class that defines the properties and behavior of the data that you present to the user. Anything that the user expects to see if they leave your app and come back later (or if they refresh the page) should be represented by a model.

For every model in your application, create a subclass of DS.Model:

1
App.Person = DS.Model.extend();

After you have defined a model class, you can start finding and creating records of that type. When interacting with the store, you will need to specify a record's type using the model name. For example, the store's find() method expects a string as the first argument to tell it what type of record to find:

1
store.find('person', 1);

The table below shows how model names map to model classes.

Model Name Model Class
photo App.Photo
adminUserProfile App.AdminUserProfile

Defining Attributes

You can specify which attributes a model has by using DS.attr.

1
2
3
4
5
6
7
var attr = DS.attr;

App.Person = DS.Model.extend({
  firstName: attr(),
  lastName: attr(),
  birthday: attr()
});

Attributes are used when turning the JSON payload returned from your server into a record, and when serializing a record to save back to the server after it has been modified.

You can use attributes just like any other property, including as part of a computed property. Frequently, you will want to define computed properties that combine or transform primitive attributes.

1
2
3
4
5
6
7
8
9
10
var attr = DS.attr;

App.Person = DS.Model.extend({
  firstName: attr(),
  lastName: attr(),

  fullName: function() {
    return this.get('firstName') + ' ' + this.get('lastName');
  }.property('firstName', 'lastName')
});

For more about adding computed properties to your classes, see Computed Properties.

If you don't specify the type of the attribute, it will be whatever was provided by the server. You can make sure that an attribute is always coerced into a particular type by passing a type to attr:

1
2
3
App.Person = DS.Model.extend({
  birthday: DS.attr('date')
});

The default adapter supports attribute types of string, number, boolean, and date. Custom adapters may offer additional attribute types, and new types can be registered as transforms. See the documentation section on the REST Adapter.

Options

DS.attr takes an optional hash as a second parameter, current options are:

  • defaultValue: Pass a string or a function to be called to set the attribute to a default value if none is supplied.

    Example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    var attr = DS.attr;
    
    App.User = DS.Model.extend({
      username: attr('string'),
      email: attr('string'),
      verified: attr('boolean', {defaultValue: false}),
      createdAt: DS.attr('string', {
          defaultValue: function() { return new Date(); }
      }
    });
    

Defining Relationships

Ember Data includes several built-in relationship types to help you define how your models relate to each other.

One-to-One

To declare a one-to-one relationship between two models, use DS.belongsTo:

1
2
3
4
5
6
7
App.User = DS.Model.extend({
  profile: DS.belongsTo('profile')
});

App.Profile = DS.Model.extend({
  user: DS.belongsTo('user')
});

One-to-Many

To declare a one-to-many relationship between two models, use DS.belongsTo in combination with DS.hasMany, like this:

1
2
3
4
5
6
7
App.Post = DS.Model.extend({
  comments: DS.hasMany('comment')
});

App.Comment = DS.Model.extend({
  post: DS.belongsTo('post')
});

Many-to-Many

To declare a many-to-many relationship between two models, use DS.hasMany:

1
2
3
4
5
6
7
App.Post = DS.Model.extend({
  tags: DS.hasMany('tag')
});

App.Tag = DS.Model.extend({
  posts: DS.hasMany('post')
});

Explicit Inverses

Ember Data will do its best to discover which relationships map to one another. In the one-to-many code above, for example, Ember Data can figure out that changing the comments relationship should update the post relationship on the inverse because post is the only relationship to that model.

However, sometimes you may have multiple belongsTo/hasManys for the same type. You can specify which property on the related model is the inverse using DS.hasMany's inverse option:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var belongsTo = DS.belongsTo,
    hasMany = DS.hasMany;

App.Comment = DS.Model.extend({
  onePost: belongsTo('post'),
  twoPost: belongsTo('post'),
  redPost: belongsTo('post'),
  bluePost: belongsTo('post')
});


App.Post = DS.Model.extend({
  comments: hasMany('comment', {
    inverse: 'redPost'
  })
});

You can also specify an inverse on a belongsTo, which works how you'd expect.