Ember and TodoMVC on Rails

With all the attention client side MVC frameworks are getting, I decided it’s time to have a real look at one of them and decide for myself if the hype is worth it.

I’m sure many of you have been playing around with these frameworks while watching others dothesame. These short dabbles tell you little about what it’s like to build something useful. In this piece, I will be exploring what it’s like to build something of actual value.

--ADVERTISEMENT--

Choosing the right MVC framework may seem difficult. There is Backbone.js, Angular.js, Ember.js just to name a few. The pragmatic Rails developer in me evaluated decided that Ember.js is the most Rails friendly framework. It integrates well with Rails and it’s a good fit when switching from backend to frontend.

To build something interesting and also not re-invent the wheel, we will be building on top of the TodoMVC application. It’s the same application that is used as an example in the official ember guide. Our version will focus on how to build and expand it in the following ways:

move to a Rails project

use Rails as its backend storage

add authentication

add private lists for authenticated users

add protected sharing of lists

There is a lot of ground to cover, so this will take a couple of posts. Today, we will cover moving the app over to running inside a Rails project and using Rails for backend storage.

TodoMVC in Ember

The TodoMVC application is used as a universal example to compare frontend javascript frameworks. It has just enough functionality to show off the framework while, at the same time, being instantly familiar to any potential developer. Let’s briefly go over the features.

The app displays a list of Todo items with a text field at the top. You can add new items to the list using the text field. Individual items can also be edited by double clicking on them and removed by using a remove icon that shows up when you hover. All the todos can be marked done using the checkbox nex to the input.

Below the list there is a counter of incomplete items and a filter to show all/active/completed tasks. Finally, you can remove all completed items from the list using a ‘clear completed’ button on the bottom.

This article is not going to over every detail, as there is an excellent article on the official ember guide for that. Here, the focus is on a high level overview of how the parts fit together, making it clear what goes where as we port the example to fit inside a Rails project.

The base template is the place to start to familiarize yourself with an Ember app. This template is where it all comes together: You get an overview (from the script tags) of the size of the application and where things are located. The following excerpt is from the TodoMVC application:

For the most part, it looks like a standard HTML5 document with a lot of javascript. The single non-standard part is the x-handlebars template. The code is omitted here, but is discussed in the official ember guide. Having it inside the HTML like that is fine for small apps, but we’ll be extracting it out as a part of the move to Rails.

The javascript imports are two-fold: The first part is importing library files needed for an Ember app to run, while the other is the Ember app itself. Both of these are discussed in greater detail in the guide, so refer to it for more information.

Setting Up Rails

Rails has good support for hosting Ember applications. All you need to do is include the ember-rails gem in your Gemfile and generate setup files.

The generator creates an ember folder structure under app/assets/javascripts. The current version is not perfect and some small tweaks are needed to finish setup.

First, remove the original app/assets/javascripts/application.js. Then, add the following two lines to the very top of app/assets/javascripts/application.js.coffee to load jQuery before loading Ember.

#= require jquery
#= require jquery_ujs

To have a root page to open, add the following to the config/routes.rb

Rails.application.routes.draw do
root to: 'application#index'
end

Also, add an empty app/views/application/index.html.erb. This is a good starting point using the default ApplicationController to render the index action without any more code. Start up the Rails app (rails s) and point the browser to http://localhost:3000 to make sure everything is hooked up.

Moving TodoMVC into Rails

It’s time to copy over the TodoMVC application into our Rails application. The resulting code is on github, if you want to jump to the end.

Start by copying the handlebars template discussed earlier to the app/views/application/index.html.haml. Edit the app/views/layouts/application.html.erb file by removing the turbolinks references and moving javascript_include_tag after the yield inside the body tag. For optional credit, we can remove turbolinks from the Gemfile because we will not be using them.

Complete the migration by copying the following files and converting them to CoffeeScript.

TadaEmber.Store = DS.Store.extend()
# Override the default adapter with the `DS.ActiveModelAdapter` which
# is built to work nicely with the ActiveModel::Serializers gem.
#adapter: '_ams'
TadaEmber.ApplicationAdapter = DS.LSAdapter.extend
namespace: 'tada-emberjs'

Almost done. Copy over bowercomponents/ember-localstorage-adapter/localstorageadapter.js to app/assets/javascript/localstorageadapter.js and add the following line to the top of app/assets/javascript/tadaember.js.coffee

#= require ./localstorage_adapter

Finish the transformation by copying over the contents of the script tag in app/views/application/index.html.erb into the app/javascripts/templates/todos.hbs. Finally, copying the css and images from the original code to our assets directory will add some styling.

Adding Rails at the Backend

The list holds its data inside localstorage of the browser that is currently running the app. Opening the app in another browser will cause the app to reset to a clean state without any todos. We will remedy this by using the Rails app as the storage provider.

First, generate a model and migrate

rails g model Todo title is_completed:boolean
rake db:migrate

Add a controller that will act as an API for the Ember app. Don’t forget about adding a resource call to the router.

Finally, add a serializer for Rails to properly serialize the model. Ember expects a string ID for every model. The ActiveModelAdapter will handle conversions between the snakecase is_completed comming from the JSON and the camelcase isCompleted that is used in the Ember app.

Conclusion

We have successfully migrated the TodoMVC app from being a standalone app to running inside Rails. We have also moved away from local storage and are storing data in Rails. In future posts, we’ll tackle adding authentication and the ability to share the list via a url.