1 Introduction

Ember.js is an exciting and popular JavaScript framework for building web applications. Created to make websites with heavy client-side functionality easier and faster to develop, Ember is currently in use by companies like Groupon, Yahoo, and Square.

Ember can be used as a front end to any server-side stack, but today I’m here to discuss how to avoid some common pitfalls when using it with my personal favorite web framework: Ruby on Rails. Though Ember and Rails make a great pair, it’s easy to get a little lost in the early days as you find your way around. Well, I did, anyway. This is your chance to learn from my mistakes so you can get to making your own mistakes a little more quickly.

Shall we begin?

2 Ember isn't Rails

Yeah, yeah, I know. That sounds obvious. But I promise: Ember is way less Rails than you think it is, and assuming the two frameworks go about their business in the same way can get you into trouble fast. Yes, they both look like model-view-controller style frameworks, but the roles played by those components in Rails are different enough that it might be a good idea to forget what you know for a bit while you’re getting to know how Ember works.

In Rails, the Controller is responsible both for gathering the requested data and for handing that data off to the view. In Ember, those duties are split between a Route object and a Controller object. The Route is where you’d request the Model from your Rails server (or from an external API), which would then be handed off for the Controller to process.

So, let’s say you were building a page to display a user profile. You’d create a Route object, and use the model hook to get the data you needed.

App.UserRoute = Ember.Route.extend({ model: function(params) { return this.store.find(user, params.user_id); } });

What’s happening is that when a URL leads to the user profile, the Route object calls the function defined in the model hook, and anything returned by it is attached to the Controller as its primary Model. An Ember Controller, unlike one from Rails, is primarily used to provide the logic used to access data from that Model.

If that User had separate first_name and last_name properties, but you wanted to offer a way to show a full name, you might use a controller method like this:

App.UserController = Ember.ObjectController.extend({ fullName: function() { return this.get("first_name") + " " + this.get("last_name"); } });

Another place where Ember terminology conflicts with Rails is with Views. Though Ember does have a View object, the thing that actually displays the data your Controller has ready for you is a Template. Ember uses Handlebars as its templating engine, and it’s with this that you’ll do the work you’re used to doing in an ERB or Haml (or whatever poison you prefer) View.

3 Where does it go: view or controller?

Okay, so if Ember has Views, but doesn’t use them to display anything, what exactly do they do? My misunderstanding of Ember Views stuck around longer than almost anything else in the framework, and I’m still untangling things I did wrong because of it. Views are very easy to use for things they aren’t meant for. Specifically, it’s easy to start putting things in the View that really belong in the Controller, and vice versa.

Luckily, the “What are Views?” question is pretty easy to answer. There are two things you might use them for:

Creating reusable components; and Setting up logic to handle events.

If your users had profile pictures, and you wanted to display those pictures on lots of different pages (y’know, like not just on the user profile page), you might want to set that up as a View. Especially if you wanted that profile picture component to have some event logic behind it. Say you wanted people to be able to click the picture to pop up a larger version of the image. Your View could wait for a click event to hit the picture, then execute whatever logic you want as a result.

Hold up, though. This is where I got turned around and put code in all the wrong places. A View is perfect for catching the browser event, but most of what you want to do as a result would go in the Controller.

Basically, your View catches the click, then sends the event up to the Controller.

App.ProfilePhotoView = Ember.View.extend({ click: function(evt) { this.get('controller').send('expandProfilePhoto'); } }); App.UserController = Ember.ObjectController.extend({ actions: { expandProfilePhoto: function() { // Get the expanded picture and display it // We'll talk more about what to do here later } } });

See that actions property in the UserController? Any methods you define in there can be called by the View with send .

Ember won’t stop you from putting a lot of logic into that click event that really belongs elsewhere, but you’ll save yourself a lot of headaches if you let the Controller handle it.

4 Ember isn't jQuery, either

One thing that really tripped me up in my early days of Ember was getting my head out of the jQuery world. As a Rails developer, I’d spent years wiring up events in jQuery, and I’d gotten used to thinking about event handling and data binding as something to be handled very procedurally. I’d catch a click, make an AJAX call to the server, then take pieces of the returned data, then update page elements as needed. If I wanted to display a calculation based on user input, I’d wait for a change event, run the calculation on the number, then update the result field(s) with the output.

Though you could write something similar in Ember (and there was this time I did and it was really embarrassing), Ember wants to go about its business in the opposite way. Instead of responding to an event by updating a field, you’d bind that field to a property in your Controller and let Ember handle keeping things updated.

This might be easier to explain with an example. If we set up a controller with two properties, number and timesTwo , like so:

App.NumberController = Ember.ObjectController.extend({ number: 1, timesTwo: function() { return Number(this.get('number')) * 2; }.property('number') });

Then, in our template, added an input box bound to the Controller’s number property, while also displaying the timesTwo property…

{{input type="text" value=number size="50"}} x2 = {{timesTwo}}

…what would happen is maaaaagic!

Okay, not magic, but what’s going on is a cool inversion of what jQuery types like me would expect. Because we bound the input to number , any updates to it also updates the Controller’s number property. And do you see that property(‘number’) at the end of our timesTwo method? That tells Ember, “Hey, treat this as a property, and update me any time number updates!”

Because we’re able to bind properties into our templates, we don’t have to worry about making sure every event updates every field that might be affected. You just update the part you want and let Ember handle the rest.

No, really, Let Ember handle things! Which brings me to our next topic…

5 Don't write code you don't need

I’m lazy. You might be lazy, too. You don't have to deny it. It’s cool. This is a judgment-free zone. And you know what? The Ember core team benevolently did a great deal of work to let us get out of writing a lot of the tedious boilerplate that takes up so much of our coding time. The problem is that it’s really easy to forget what we need to do and what Ember will do for us if we’d just get out of its way.

A quick recap on how Ember’s order of operations: A user hits a URL, which Ember’s Router recognizes and passes to a Route object. That Route sets up a Controller and supplies it with a Model, which provides the View layer (represented by a Template) access to the data. Any properties defined by the Model are available to the Controller – so, for instance, if User has first_name , your Template has direct access to it through the Controller.

If you were building a User profile page that did nothing but display information provided by the model, you might think you need to build the shell of a Controller object to make sure it exists. You know, like this:

App.UserController = Ember.ObjectController.extend({ });

I mean, you have to in Rails, right? Even if a Controller action doesn’t actually do anything, you need to define the method for it.

Not with Ember, though.

Much of Ember’s magic is based on naming conventions. If you have a UserRoute, by default Ember will pass off to a UserController, and that will look for a Template in users/user.hbs. So far, very Railsy. But what Ember can do in addition is generate the Controller for you if you haven’t defined it.

In other words, if all UserController does is pass a Model to user.hbs, then you don’t need to define UserController at all. Ember will, through the power of naming conventions, simply generate that Controller for you.

And it won’t just do it for Controllers. If your Route object doesn’t need to do anything (if, perhaps, your home page route just displays static content and no data is needed), don’t write it! If your user.hbs template isn’t actually going to display anything (hey, I don’t know why you want the template to be blank, but like I said: no judgment), don’t create the file! Ember will happily display nothing for you all on its own.

At first glance, Ember can feel like it demands a lot of pointless, boilerplate coding. But that’s only because, at first glance, you might not have realized how much Ember will do for you.

6 Properties and observes

Remember when I was talking about all the cool data binding Ember did for us?

Oh, c’mon, it was only 2 problems ago! Fine, fine. Scroll back up and refresh your memory. I’ll wait.

Okay, back with me? Then let’s talk about yet another thing that can be a bit confusing, especially in your early days of Embering: property vs. observes .

Underneath the hood of Ember, the thing that makes all that exciting data binding work is done by Observers. Ember’s Observer functionality watches for changes, then fires off events (or updates data) when something happens. Easy enough, right? The part that can get a bit confusing is that Ember allows you to respond to changes in two ways.

We saw the first one above: the property method. property lets you use the return value of a function as if it was a static value. Stick property at the end of a function, and you can bind to it in your template and display the value there.

But what about observes ? How does that work? Well, let’s look at some code:

App.UserController = Ember.ObjectController.extend({ fullName: function() { return this.get("first_name") + " " + this.get("last_name"); }.property('first_name', 'last_name'), nameChanged: function() { console.log("New name! New name!"); }.observes('first_name', 'last_name') });

We’ve got two methods in our controller. The first, fullName , is defined as a property , and it’s watching both first_name and last_name for changes. The second, nameChanged , is watching the same two properties, but it’s doing it with observes .

Whenever first_name or last_name change, two things are going to happen. The first is that the fullName property is going to update, so that anything in the template bound to it will reflect those changes. In other words, the property method doesn’t act on anything, it just provides an updated value to anything watching it.

When observes sees a change, on the other hand, it’s meant to perform an action. You can’t bind anything in your template to a method that executes observes . Whatever is executed within the body of the method is all that happens. In this case, we’re logging to the console that something has updated.

Generally speaking, I find myself using property a lot more than observes , but observes is great whenever you need something to happen beyond just updating other values. As an example: One way I’ve used observes is to trigger form validation logic.

And yeah, you technically could use property to perform logic and update a value, but then you’d just be repeating my bad decisions, and the whole point of this is to use me as a cautionary tale.

7 You don't need Ember data

Here’s something you might not know about Ember.js: It doesn’t come default with a data library. It may sound a little strange that a model-view-controller framework doesn’t come prepackaged with what a Rails developer would think of as model. In fact, a lot of the early complaints leveled at Ember (in the days when Ember Data was undergoing significant, break-your-application changes, like, all the time) was that if Data wasn’t ready, what was the point of using Ember at all?

Way back in Ember Problem 1, I dropped this code:

App.UserRoute = Ember.Route.extend({ model: function(params) { return this.store.find(user, params.user_id); } });

That code is using Ember Data. But it doesn’t have to be. See, the misunderstanding is that the model hook needs to return a proper Ember Model object. The truth is, it could return a plain JSON object and Ember would be just as happy. I could just do this…

App.UserRoute = Ember.Route.extend({ model: function(params) { return { first_name: "Eric", last_name : "Sipple" }; } });

…and our Controller gets a Model just the same. I use Ember Data because it provides a way to persist that data, and gives access to a really nice REST adapter, but there are a lot of people who are more than happy to deal with the REST parts on their own, and build a data object model that suits them better than what Ember Data does.

Ember needs data, sure, but it doesn’t need Ember Data.

8 Rails is your API, not your web server

I know we’re focusing on Ember, but I’d be remiss if I didn’t deal with a conceptual problem a lot of people hit when they’re getting started: Rails is not a website framework anymore. It’s your API.

You won’t be sending Ember formatted HTML. You won’t be rendering things in ERB or Haml templates. In fact, from here on out, you can pretty much ignore Rails’s view folder. What Ember wants from Rails is JSON. Ember is going to call a route in your Rails app, and Rails is going to get the data it needs, serialize it, and send it back.

There are a lot of ways to make that happen, but my personal preference is ActiveModel Serializers. It’s a gem you can add to your project, and it makes outputting to JSON wicked easy. The documentation is available here, but let me walk you through the basics.

If our Rails server was sending back the User information for our Ember application’s profile page, your controller might look like this:

class UsersController < Devise::SessionsController def show @user = User.find(params[:user_id]) respond_to do |format| format.json { render json: @user } end end end

We’ve got our show method, and it gets a User object, then calls render json on it. From here, ActiveModel Seralizers picks it up. To make that work, you create a _serializers- folder in your app directory, and – in this case – create a _userserializer.rb file that looks like this:

class UserSerializer < ActiveModel::Serializer attributes :first_name, :last_name end

And that’s it! Rails is now an API for your Ember application. Down with ERB! Down with Haml! Long live JSON!

9 Not using promises

If you decide to use Ember Data like I did, you can go a long time without realizing what a Promise is and why you might need to use it. For simple applications, Ember Data’s REST adapter can handle all the asynchronous calls to your Rails server and completely insulate you from worrying about what happens when the server takes longer to respond than you expected.

Unfortunately, even applications we think are going to be simple always seem to end up careening down a Black Diamond ski slope at some point or another.

If you ever need to make a call back to the server outside of a Route object’s model hook, you’re going to need to make sure your application knows what to do when that call succeeds, what to do if it fails, and not to do anything about that call until it returns. For that, Ember gives us access to Promises.

If you’ve used jQuery for AJAX calls, this code is probably familiar to you:

$.ajax( "/user/4" ) .done(function() { alert( "success" ); }) .fail(function() { alert( "error" ); }) .always(function() { alert( "complete" ); });

That lets jQuery make an Ajax call, perform the done function if it succeeds, the fail function if it doesn’t, and to call always no matter what happens. And none of those methods get called until the AJAX call is done.

Promises are what lie behind the Ember Router when it makes a call in the model hook, pauses for it to resolve, then resumes operation to set up the controller. And Promises are what we can use if we need to make calls of our own outside of the router.

Going back to our profile photo example from earlier, we could use Promises to ensure that we wait for our Rails server to respond with the expanded photo, and to react appropriately whether it succeeded or failed. In fact, if we’re using Ember Data, we have to rely on promises.

App.ProfilePhotoView = Ember.View.extend({ click: function(evt) { this.get('controller').send('expandProfilePhoto'); } }); App.ProfilePhotoController = Ember.ObjectController.extend({ actions: { expandProfilePhoto: function() { this.get('store').find('profile_photo', this.get('user_id')).then( // fulfill function(answer) { // Display expanded profile photo }, // reject function(e) { // Display error message }); } } });

The find method in Ember Data doesn’t return the object it’s found. What it returns is a Promise. To use that Promise properly, we can chain a then method onto the end. Essentially, Promise.then() says, “Once you’re done, depending on what happens, these are the callbacks I want run.”

The first call back we provide is the fulfill method – what to do if it succeeds. The second is what happens if it rejects, or errors out.

If you don’t lean on Promises, you feel tied to only using Ember’s model hook in the Route to get data from the server. That gets limiting fast, and will lead you into some awful dead ends. Trust me. I’ve ended up in a lot of them.

10 Not using Ember inspector

If you're developing an Ember app and not using Tilde's awesome Ember Inspector browser extension, you're probably putting yourself through a lot of unnecessary pain. Available for Chrome, Firefox, and Opera, Ember Inspector adds indispensable debugging tools to your browser's developer suite.

Ember Inspector provides access to all active Ember components. You get a tree of currently loaded Controllers and Views, their related Models, and a breakdown of available Routes.

Seriously. Go install it if you haven't. It's saved me more times than I can count.

11 Wrapping up

Ember.js is a huge topic, and no one article can cover all of its features -- nor the problems you might run into as you get to know them. I hope this post covered some of the top ones, and gave you some ideas on how to get around them as you move forward with your own Ember applications. Good luck, and happy coding.