Blog article

A few days ago, following long discussions, Rails API was merged into Rails master branch.

Because of that, in our latest post we discussed how to build an API only application. We’ve also shown how to integrate it with a client-side application implemented using Backbone. If you’ve missed this post, check it out and learn more about how to integrate Rails API with an Backbone application.

In this post, we are going to show how a very similar client-side Ember application can be integrated with the same backend application implemented using Rails API. Like in our previous post, we are going to use the TodoMVC application.

In addition, we are going to comment about some issues that were fixed in Rails and Active Model Serializers in order to make the integration easier. These improvements were the result of testing Rails API with an Ember application, as part of our efforts to make it work properly with some of the most popular JavaScript frameworks.

Building the Backend

Generate the Rails API only application

First of all, we need to generate a new Rails API only application from scratch. Rails 5 is not released yet, so we have to clone the Github repository and generate our application directly from the source code.

git clone git://github.com/rails/rails.git
cd rails
bundle
bundle exec railties/exe/rails new /tmp/my_api_app --api --edge

In case you want a detailed explanation about the list of directories and files generated by this command, please take a look at our previous post.

However, if we compare with what was described in our previous blog post, we can see a subtle difference in the generated Gemfile: the active-model-serializer gem version changed from 0.10.0.rc1 a 0.10.0.rc2.

The new Active Model Serializer release candidate includes a new adapter that works properly with the Ember’s RESTAdapter. This addition simplified a lot the integration of our Rails API only backend and the Ember client-side application.

Scaffolding the Todo resource

The Todo items in the Ember application have two attributes: a string title and a boolean isCompleted. The following step to build our backend application is precisely to add a resource representing these Todo items.

We can do it just running the rails generate scaffold command:

bin/rails g scaffold todo title isCompleted:boolean

Since we’re now using a new version of the active-model-serializer gem, specifically the version 0.10.0.rc2, the scaffold command generates the serializer file for this resource. At the time of writing our previous post, we had to run another command to generate the serializer. It is now changed to be automatically run along the scaffold generator. In fact, this was an enhancement implemented only a few days ago.

Don’t forget to run bin/rake db:migrate to update the database schema.

Choose the appropriate JSON serialization format

Our Rails API only application is going to respond incoming requests in a given JSON format. The process to convert the data into this format is called serialization and this will be possible in our backend application thanks to Active Model Serializer adapters.

By default, Active Model Serializer uses a format provided by the flatten_json adapter which is a very simple format that only includes the list of attributes without any additional metadata about the data being serialized. For instance, using this adapter, a Todo item would be serialized like:

{
  "id": 1,
  "title": "Todo 1",
  "isCompleted": false
}

Luckily, we have some adapters shipped with Active Model Serializer in 0.10.0.rc2, giving us a lot of flexibility. In particular, we need to pick a JSON format matching our Ember application. We can achieve that by selecting a format that works well with the Ember’s RESTAdapter. The main requirement specified by the RESTAdapter is the presence of the root object’s key as part of the JSON payload, as it is explained in the Ember RESTAdapter documentation. It means we want to serialize a Todo item like this:

{
  "todo": {
    "id": 1,
    "title": "Todo 1",
    "isCompleted": false
  }
}

This is easy to do with Active Model Serializer if we choose the json adapter instead of the flatten_json. We can configure it by creating a new initializer file config/initializers/ams_json_adapter.rb including the following line:

ActiveModel::Serializer.config.adapter = :json

At this point, the backend application should be ready, so it’s testing time! Start the web server with bin/rails s and let’s create our first Todo using curl:

curl -H "Content-Type:application/json; charset=utf-8" -d '{"todo": {"title":"Todo 1","isCompleted":false}}' http://localhost:3000/todos

The API application should return the created item serialized in JSON format, including the root element:

{"todo": {"id":1,"title":"Todo 1","isCompleted":false}}

Now, let’s get the Todo items list:

curl http://localhost:3000/todos

and the response should look like this (note the root element in plural):

{"todos": [{"id":1,"title":"Todo 1","isCompleted":false}]}

Integrating with the Ember client-side application

We want to have both components working together, integrating our Rails API only application with the Todo list frontend application implemented with Ember.

The original implementation from TodoMVC is our starting point, but we must do a few changes to have it working properly with our backend. In fact, the TodoMVC Ember example uses the browser local storage to persist Todo items, but we want to have our Rails API application doing this job.

After downloading the Ember application code from TodoMVC, we need to have a newer version of the ember-data library to integrate properly this frontend application with Rails API. If you’re interested on reading more about this, we’ve opened a pull request on the TodoMVC repository. So whilst the pull request is not merged or ember-data updated in other way, we need to update this library by hand using curl:

curl http://builds.emberjs.com/release/ember-data.js > node_modules/ember-data/ember-data.js

We have now all the vendored JavaScript code updated, so we are prepared to connect the frontend with our Rails backend. We configure that by changing the Ember adapter from LSAdapter (local storage) to RESTAdapter. You can learn more about Ember adapters in the Ember documentation page.

Let’s replace the following piece of code in the js/app.js file:

  Todos.ApplicationAdapter = DS.LSAdapter.extend({
    namespace: 'todos-emberjs'
  });

with the RESTAdapter’s definition pointing to our backend:

  Todos.ApplicationAdapter = DS.RESTAdapter.extend({
    host: 'http://localhost:3000'
  });

Finally, we have to configure CORS in the Rails API only backend because both applications will run in different domains (we will test the backend in localhost:3000 and the client-side application in localhost:9000).

In brief, we need to uncomment the rack-cors gem reference in the Gemfile, run bundle install and finally put the following code in the config/initializers/cors.rb file:

# Avoid CORS issues when API is called from the frontend app
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests

# Read more: https://github.com/cyu/rack-cors

 Rails.application.config.middleware.insert_before 0, "Rack::Cors" do
   allow do
     origins 'localhost:9000'

     resource '*',
       headers: :any,
       methods: [:get, :post, :put, :patch, :delete, :options, :head]
   end
 end

You can read more about how to setup CORS in our previous post.

We are now ready to test the whole application! Run the backend server with:

bin/rails s

and start a simple web server to test the Ember application:

ruby -run -e httpd . -p 9000

You can already try it out and start adding your first Todo items, just browse to localhost:9000.

Closing Thoughts

I hope this example illustrates another possible use of the new Rails API functionality that will be included in Rails 5.

We’re aware there’s still room to improve the experience. If you have the chance to try it out, we invite you to comment about your experience with Rails API.

We’d love to hear your feedback!

Resources

You can find the backend and frontend applications that we built in this article in Github:

The Ember application was borrowed from the TodoMVC project.

If you’re looking for a more modern & idiomatic implementation of the Ember TodoMVC check out this one. A piece of advice: the code in master doesn’t fully work when it’s integrated with our backend. There is an issue where Todo items are not completed in the Rails API only application when clicking on checkboxes. As far we tested, this open pull request fixes the problem.