Connect your Ember frontend app to a Rails API
Right now, we've got some objects displayed on our page, but they're currently hard coded into the ember route, and we want to connect it to a rails API, so let's go ahead and create that. rails new rails-api --api That will create a rails app. It will be a little bit different than a regurlar rails app, it will remove the jquery and the turbolinks gems. Some other differences are in the application controller, so it will have config.api only set to true. It won't check for csrf protection, and it will inherit from ActionController::API so now that we've generated it, let's go in there and get startted. We'll start off with a rails migration, and we will create monsters table, and I know there's more efficient ways to do this, but I'm going to go ahead and edit this in the file, so we'll create a string for the name, and then we'll create an integer for the level, and then we'll run that migration. Next we'll create our monster model, at monster.rb ant it will inherit from the ActiveRecord::Base, and there's not much we need to do there besides just declare it. Now, off screen, I'm going to go into the rails console, and create several monsters. So we have four monsters in our database now, and we'll want to display them in JSON to render them at a certain url that our ember app can look at. We'll start by going to our routes file, and adding the monsters resource. Then, we'll add a controller for the monsters, and we'll have our index route, which is very simple
class MonstersController < ApplicationController def index render json: Monster.all end end
That will take all the monsters in the database and show them in JSON format when we call mosnters.json. For our ember app and our rails app to connect, they have to both be reaching out and coordinated so that they're connecting in the right way. This is our first attempt from the rails app to make that connection, it's not going to be our final attempt. We're going to change a little bit later, but first, let's make some progress on that ember app. Let's get them closer and ee where they do and don't align. We'll start in our application route. So right now we're hard coding all this, but we're going to want to do something like this. This is actually the final API that we're going to be using and it's really simple. So we call to our store, that's our ember datastore, which is really useful to have around when you have a large amount of objects keeping track of, and you're going to find all of the monsters. We're going to find them all from the server and we're going to tell the server how to do that. First let's see what that does right now. Right now, it says there is no model found for Monster, so let's go ahead and make that. So we're going to have a monster model, and what this does, is it defines what is and isn't in a monster model, so we're going to give it the different attributes, such as name, and we're going to use the attribute function here, and say that name is a string, so it will be coerced into a string. Whatever is coming over the wire, and usually strings don't need much coercion, but sometimes numbers do, so the level, even if it comes over as a string, it will be coerced to a number, so we know what we're dealing with. Something to note as well is that if something isn't defined as an attribute, then our ember data model will not show it. Even if it's coming through via the JSON. All right, so let's see what this does. We're getting a different error message now. It says we can't find localhost:4200/mosters. So when we call return this.store.findAll('monster');, it's trying to find it at the monsters route. It's trying to find JSON there, but it's trying to find it in localhost:4200, which is where we're hosting our ember app, and not 3000, where we're hosting our rails app, so what we can do is go into the .ember-cli file, and this will let us set "proxy": "http://localhost:3000" What that does for us is well first we're going to restart our ember app. So anytime you change some configuration, then you have to restart it from scratch, because live reload won't work there. All right, so we're making some progress, and now it has a different error. It says: Normalized response must return valid JSON API document, so it's expecting our monsters json to be in the JSON API format, and this is not the JSON API format. What we have to do is make the format that ember expects, and the format that rails gives out the same. We can do that by changing either end of it, and actually we're going to go ahead and change both ends. On the rails side, we're going to use the active_model_serializers gme. On the ember side, we're going to use the active_model_adapter add on. We'll start witht the active_model_serializers gem. It recommends that you use 0.10.0, but I happen to know that 0.8.0 is the one that works best with the ember data active_model_adapter add on. So we will add the active_model_serializer gem in our Gemfile. We will run bundle install. Then we will restart our rails server, and we'll generate a serializer, and it will be the monster serializer. Let's go to that monster serializer. The monster serializer comes with an id attribute, and we can have other attributes, like name and level. Now let's go ahead and look at here we have monsters as the array. So the array is labeled now, previously this monsters key wasn't there. Now it's time to change things on the ember side. So we'll go ahead and install the active_model_adapter, and of course, we're going to have to restart that ember server anyways so there we go, and then we'll have to create a new file, so it will be in the adapters folder, and it'll be the application adapter, and so you can have individual adapters for each types of model that you have, so if you have a monster thing, if you have a level thing, then you can adapt all of them separately. But the application adapter is what applies to all of them, and so we'll tell them: All right, instead of json API adapter, we want you to use the active_model_adapter, and looky there, everything is connecting correctly. Let's trace back everything that's involved, so we create a table of monsters in our database, and we have our monster controller to-- well, if we provide data about relationships and stuff like that, and then, in routes, it says that we have monsters resource, and that will default to the monsters controller, and in the index route, we're returning all of the monsters, and then we go to our serializer, which allows us to say which attributes we're going to send out, and the gem that let's us do this of course is active_model_serializer in the 0.8 line. Then in the ember side, we have our active_model_adapter, which comes from an add on, telling us what form to expect the json in. And then we have our monster model, which tells us what attributes we're willing to accept, and finally, in our application route, we're using the store called findAll for the monsters, and that tells ember to go look at the slash monsters route, in our proxy, which is defined in .ember-cli. Then the monsters that come from this end up being put into the template, and looped through this each block, and then displayed, giving us finally what you see here. I know this seems like a lot, and that's because it is, when we're setting up the first time, but when we're doing this for other things, all we'll have to see is this handle bars, and this statement. This is the simple core that we did all the set up to get to, and now that you have the connection to rails, then communicating along that connection should be much easier from now on. In the next video we finally get to start with some of the fun stuff. We'll be making edits in real time and having them save to the rails server. I'll see you then.
Transcript written by Miguel
Great.. introducing ember to me..
I was stuck at that point proxy to localhost.3000. Then I got it working.
fill the .ember-cli => "proxy": "http://localhost:3000" /// not working
throw "Error when parsing file in " + path + ". Make sure that you have a valid JSON."
Can you pls. comment? Thanks
Awesome series! I've been wanting to get started with Ember and this video series is such a great help!
On a side note: I had trouble with 0.8.1 active model serializers gem. It did not include the jsonapi adapters, rendering json objects without a root. I upgraded the active model serializers gem to 0.10.2 and it pulled in a *now* working jsonapi adapter.
Which is the ember version that you're using?
I'm running the ember server but the console is displaying what i'll show you in the image
Thanks for your help.