Converting a Model

Learn how to convert an Ember Model to native class syntax.

Summary

Converting an Ember model to native class syntax

Summary

As of Ember 3.10 (with decorator support), you can easily start converting your Ember app to use native classes. Not only will this bring your Ember app more in-line with the rest of the Javascript ecosystem, it is a required step in upgrading an app to use Octane.

A complete Octane upgrade is fairly involved, so I would recommend checking out The Ember Atlas upgrade guide for a great overview.

To convert our files, I recommend using the excellent ember-native-class-codemod.

Following the directions in the addon readme, we'll need to install two decorator addons:

ember install ember-classic-decorator
ember install ember-decorators 

and then start our app: ember serve. As you start your app, take note of what port it's running on.

We'll start with trying to convert this model file:

import DS from 'ember-data';
import Commentable from 'ember-playground/mixins/commentable';

export default DS.Model.extend(Commentable, {
  body: DS.attr(),

  author: DS.belongsTo('user'),
  post: DS.belongsTo('post'),
});

Once the app is running, we can run the npx command noted in the codemod docs: npx ember-native-class-codemod http://localhost:4200/ app/models/comment.js.

This will take a minute to run, but at the end we see codemod output -- 1 unmodified, 0 ok Additionally we see there's a new file in our directory -- codemods.log. Inspecting this file shows nothing was added. And finally, if we look back at our model file, we can see that nothing has changed.

Looking more closely at the codemod docs, we can see it does not support methods imported from DS. We can convert our model file away from using DS import as such:

// app/models/comment.js
import Model, {attr, belongsTo} from '@ember-data/model';
import Commentable from 'ember-playground/mixins/commentable';

export default Model.extend(Commentable, {
  body: attr(),

  author: belongsTo('user'),
  post: belongsTo('post'),
});

Running the same codemod command again produces a more agreeable output from the command, a SUCCESS line in our codemods.log file, and finally, our model file converted to use native class syntax.

import classic from 'ember-classic-decorator';
import Model, {attr, belongsTo} from '@ember-data/model';
import Commentable from 'ember-playground/mixins/commentable';

@classic
export default class Comment extends Model.extend(Commentable) {
  @attr()
  body;

  @belongsTo('user')
  author;

  @belongsTo('post')
  post;
}

We can see we're now using native JS class syntax to define our model class, and it has an automatic name generated -- Comment. The model attributes, attr and belongsTo, are now preceded by and @ which indicates a decorator. These attributes act exactly like the old ones, just with slightly different syntax.

We've also got a @classic decorator added above the class definition. This is something that is added to every file converted by the codemod by default, and helps with the Octane transition. It acts as a bridge between old ember classes and the new, vanilla JS classes. If your new class has no deprecated ember quirks, you can go ahead and remove the @classic.

In this case, we've got a mixin that we still need. We won't be able to remove the @classic decorator for this class until we can refactor away from the mixin.

Questions?

Send us a tweet:

Or ask us in Inside EmberMap, our private Slack workspace for subscribers.