Note: I'm going to assume you already have knowledge on Elixir and have everything installed. Also, you should have gone through the ember super rentals tutorial, or have some EmberJS knowledge.

You can find all of the code on the Github Repository.

// versions used at the time of writing ember-cli: 2.2.0-beta.6 node: 5.5.0 npm: 2.14.10 elixir: 1.2.1 phoenix: 1.1.3

Setup

The main thing to note here is that the ember and phoenix applications are completely separate. Here are some steps you need in order setup both the EmberJS app and the Phoenix backend API.

Create main directory mkdir blog.

Go to that directory cd blog.

Generate the Phoenix app mix phoenix.new backend --no-brunch. Since we are not compiling any assets on the Phoenix app, we don't need brunch.

Generate the Ember app ember new frontend.

Setting up Ember

First up, we're going to get the Ember app setup. For now we'll just go straight to using the API as our data source, instead of using a Faker API. You'll want to be in the frontend folder at this point.

In this section we'll be focusing on creating a few files and modifying the app's configuration file.

By adding the apiHost to the configuration, we can access it at any point in our application. This is helpful for when we need to change it based on the environment and in case the endpoint changes at some point.

// config/environment.js ... if (environment === 'development') { // ENV.APP.LOG_RESOLVER = true; // ENV.APP.LOG_ACTIVE_GENERATION = true; // ENV.APP.LOG_TRANSITIONS = true; // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; // ENV.APP.LOG_VIEW_LOOKUPS = true; // Configure the API host ENV.apiHost = "http://localhost:4000"; } ...

apiHost is the host where the API lives. In this case, it would be localhost:4000, at least on the development environment.

Creating the Post Model

In order for Ember to know what kind of data we're dealing with, we need to specify a Model.

// app/models/post.js import DS from 'ember-data'; export default DS.Model.extend({ title: DS.attr('string'), content: DS.attr('string'), author: DS.attr('string') });

Creating Routes and Templates

The Router only has one entry, which is the route to display a single post item.

// app/router.js import Ember from 'ember'; import config from './config/environment'; ... Router.map(function() { this.route('post', { path: '/post/:post_id' }); }); export default Router;

You'll want to create the Route handler for the post route, which is shown below. We return the model so the post template will be able to access the data pulled in by the RESTAdapter. Don't worry if the app is not working yet, because it will once the Adapter is created.

// app/routes/post.js import Ember from 'ember'; export default Ember.Route.extend({ // give us the route params so we can access the post_id model(params) { return this.store.findRecord('post', params.post_id); } });

The template below will display the post information once the route is accessed.

{{!-- app/templates/post.hbs --}}

{{model.title}}

by {{model.author}}

{{model.content}}

We also need a place to display all the posts, so we'll take advantage of ember's index route, which we don't need to add in router.js because it's a default route. However, we do need to create a route handler for the index route, which will tell it what the model is for that route.

// app/routes/index.js import Ember from 'ember'; export default Ember.Route.extend({ model() { return this.store.findAll('post'); } }); {{!-- app/templates/index.hbs --}}

Posts

{{#each model as |post|}}
{{#link-to 'post' post}}

{{post.title}}

{{/link-to}}
{{post.content}}
{{post.author}}
{{/each}}

Creating the RESTAdapter

The main piece that ties together Ember and Phoenix is the Adapter, which is what Ember uses to connect to various endpoints and retrieve data. For this particular example I'll just be using the DS.RESTAdapter.

// app/adapters/application.js import config from '../config/environment'; import DS from 'ember-data'; export default DS.RESTAdapter.extend({ host: config.apiHost, namespace: 'api' });

As for the ember part of things, that's all we need to do. There's definitely a lot more to EmberJS than this, so I recommend you play around with it and get as far as you can. Check out their documentation, which is, in most cases very helpful. Now we can move onto the Phoenix API.

Phoenix API

To get started we first need to create the resource our API will be serving, that being Posts. Phoenix makes this initial task easy by providing a Mix task that generates some code for us. Just run mix phoenix.gen.json Post posts title:string content:text author:string. Run the mix ecto.create and mix ecto.migrate tasks.

As you will see it generates the model, views, controllers, and test files. Before we go any further, we need to change a few things within the PostView. The main thing to note in the changes is that we change data to posts and post. This is because the Ember app will be looking for a post resource, not data. We could create a REST serializer or custom adapter to deal with this, but that's not in the scope of this tutorial.

web/views/post_view.ex defmodule Backend.PostView do use Backend.Web, :view def render("index.json", %{posts: posts}) do %{posts: render_many(posts, Backend.PostView, "post.json")} end def render("show.json", %{post: post}) do %{post: render_one(post, Backend.PostView, "post.json")} end def render("post.json", %{post: post}) do %{id: post.id, title: post.title, content: post.content, author: post.author} end end

The next thing we need to change is the router. We can remove the unnecessary :browser pipeline and the default scope. We can also add the posts resources route, which is what the ember app will using.

web/router.ex defmodule Backend.Router do use Backend.Web, :router pipeline :api do plug :accepts, ["json"] end # Other scopes may use custom stacks. scope "/api", Backend do pipe_through :api resources "/posts", PostController, except: [:new, :edit] end end

Setting Up CORS

Add {:cors_plug, "~> 0.1.4"} to your dependencies. This way we can enable CORS (Cross Origin Resource Sharing), which will allow our Ember application to access the API. Run mix deps.get.

You will need to add the Plug to our main application Endpoint.

lib/backend/endpoint.ex ... plug CORSPlug, origin: "http://localhost:4200"

Create Some Posts

You can either use iex to create some posts in the database. For this, I decided to use seeds to create a few posts.

Backend.Repo.insert!(%Backend.Post{ title: "Test Post #1", content: "Some test content for the test post.", author: "User" }) Backend.Repo.insert!(%Backend.Post{ title: "Another Test POst", content: "Some test content for the test post.", author: "User" })

That's it! When you start your phoenix and ember app you will see a working app displaying some posts. If you missed anything or are unsure of what needs changed, take a look at the Repo and see what the final product is.

Although it's a pretty basic app, I just wanted to shed some light on how to get Ember up and running with a basic Phoenix API. There are definitely a lot more articles coming from me about using Phoenix with Ember and various other front-end frameworks.

Currently I'm working on a series to create a Blogging Platform using some front-end framework and Phoenix. Though, I do need to research all of the options before I start something serious. So, I'll be bringing you some shorter articles on my findings.

Hope this helps anyone who was interested in Ember and Phoenix. If you have any questions or concerns, feel free to contact me on twitter or leave a note in the comments.