Ember.js 2.0 Example App With Firebase And Login Authentication

Ember has a six week release cycle so things move fast. With that said some of my previous tutorials are a little out of date. The purpose of this post is to take all the concepts from the previous tutorials and roll them into this one.

What will this tutorial cover?

This application is an example of a blog. You'll be able to login with Twitter and add or delete posts. In additions you can leave a comment on anyone else's post.

If you'd like to follow along the code is on Github. A fully working demo can be found here.

This tutorial will cover the following concepts:

EmberFire

torii/authentication

helpers

pods

utilities

routes

models

relationships

Promises

components

templates

This tutorial is meant for beginners to intermediate developers interested in Ember.js. I'll assume you have some knowledge of JavaScript and some basics of Ember.

Versions as of this writing

As of this writing I'm using these versions of libraries:

Ember CLI v1.13.13

Node v5.3

npm v2.14.10

Ember 2.2.0

Ember Data 2.2.0

The latest beta version of Ember CLI was having issues with some of the addons so I'm using Ember CLI 1.13.13 instead of the beta.

To get the latest version of Ember and Ember Data with Ember CLI v1.13.13 delete the bower_components and node_modules folders. Then update the bower.json and the package.json files with the latest versions of Ember and Ember data. Then run npm install and bower install again.

Creating the folder structure and configuring the app

We'll assume you have Ember CLI installed. If not check out the getting started guide here.

Let's begin by creating a new application. We'll just call it blog.

$ ember new blog

This will create all the necessary files for our project.

Let's edit the .ember-cli file so we can generate files using the pods structure by default.

// .ember-cli
{
"disableAnalytics": false,
"usePods": true
}

This will make sure all files we generate are in the pod structure. If you want more information on pods check out my pod tutorial.

Next we'll edit the environment.js file so all pod files are put into a folder called features in the app folder.

You may have noticed that we have a features/post folder and a features/posts folder. This is true with user and comment as well. Unfortunately by convention model's are usually named with a singular name and the routes are plural. This doesn't quite fit in with the pod structure. There is talk here on what to do about it for the future while the pod structure is finalized. For now we'll live with it.

Update the config file for Firebase

Make sure to change the URL to the correct one from Firebase. If you don't have one already signup for an account here. It'll walk you through creating your first Firebase app.

When using Emberfire with torii we'll have access to a service called session. This session service will be used throughout the application. After being authenticated we'll be able to pull the username {{session.currentUser.username}}, uid {{session.uid}} and profileImageURL {{session.currentUser.profileImageURL}} from it. You can find more about the twitter session object here.

After installing Emberfire it creates an application adapter for us! How convenient, although it doesn't generate it in the correct location for the pod structure. We'll need to move it to the right place.

$ mv app/adapters/application.js app/features/application/adapter.js

Configuring Torii

Torii is an authentication library for Ember. It's the preferred way to work with authentication with Emberfire.

This will configure torii so we can use authetication in our app. You can take a sneak peak of how it's implementing everything by looking at the node_modules/emberfire/addon/torii-adapters/firebase.json file. This is where the open, fetch and close methods are defined.

The next step is to log into the Firebase dashboard and setup the User Login and Authentication tab for Twitter. I'm not going to get into details because you can find the directions here. Essentially you'll need to create a Twitter application and input the Twitter API key and API secret key into the dashboard.

After this is all setup we'll be able to use the session service throughout our application to login, logout and check authentication.

Delete non-pod structure folders

Since we are using pods we can clean up the app folder structure. Delete all the folders except for styles, features and torii-adapters. The directory structure should look like this.

features/

styles/

torii-adapters/

app.js

index.html

router.js

That's it! We'll create a few more folders for the utils and helpers later. For now this will work.

Using ES6 in our App

In my past tutorials I have used mostly used ES5 with some ES6. That's fine and it will work. With that said it's recommended to use ES6 in your Ember applications. It just makes things easier.

If you'r not familiar ES6 is the new ECMAScript standard. I've written about it here.. It adds a bunch of new features into JavaScript.

In this tutorial I'll be sticking with ES6. The three most important ES6 features I'll be using in this tutorial are:

Method Definitions

Using the new ES6 method definitions saves a little bit of time. This is the older method function syntax.

...
actions:{
submitAction: function(){
//code here
}
}

Now we can remove the function part all together.

...
actions: {
submitAction(){
}
}
...

It's just a little cleaner.

There are a few other things I'm using, but you'll notice these the most.

Configure the router

For this application we want the title of each post to be the name of the route. For example if the title of the blog post is Ember 2.0 Example App then the URL should be /ember_20_example_app. We'll use a utility to help make this possible. For now we'll create a dynamic segment called :titleURL.

The application route is already defined by default. This route is where we'll display each blog post. The posts route will display each individual blog post. The new route is where we will add new blog posts.

Defining our models

We'll be using three different models: comment, post and user. The relationships will follow these rules.

Each user will have zero or more comments

Each user will have zero or more posts

Each post will have zero or more comments

This is a very simple example as demonstrated by my UML diagram above.

The user model has a uid, which is where we will store the unique identifier that is passed from Firebase after authenticating the user. We also store the username, the avatar which is the Twitter picture, and it has many posts and comments.

Utils and Helpers

To make our job easier we can use utils and helpers. Utils are small snippets of code that we can import anywhere. It'll help us with some common tasks.

Helpers are used with templates. You might be familiar with input helpers. Ember gives us the flexibility in creating our own.

Creating an excerpt Helper

When displaying each post on the front page we'll want to just show the first 15 characters. That way the user will get an idea what the post is about. To do that we'll create a really simple helper called excerpt.

In this example we create a Ember.RSVP.Promise that resolves with either the record of the new user or the existing user record.

The purpose of this is to find if the uid passed to the function matches an existing user. If it does it returns that user, if not it creates a new one.

To accomplish this we use the Emberfire query method. The documentation is here. We have to pass in the store because the store is not injected into utils by default.

Cleaning the URL

To make this tutorial more interesting I changed the way we are storing the URL to each post. Each post's title will act as the URL. Therefore we need to clean the URL so it doesn't have any weird characters in it.

This function changes all spaces to underscores and removes all characters except a-z, A-Z and 0-9, using some regular expression.

Components

In our tutorial we want our components help with the logic for our posts. The components will allow the user to edit, delete or create new posts. It will also handle the comments.

When creating components it's a good idea to keep a few best practices in mind. One of the most important ones is data down and action up. We want to pass our models and session information down, but we don't want to mutate or change them in the component. Rather we'll send them back up to the route to be updated.

We'll be using sendAction in this example instead of closure actions. Check out Jeff's tutorial on closure actions for more information. The reason being is that you can't pass a closure action from a route. At least not until routable components lands in Ember.js. Since I have all my actions in my routes and I don't have anything in my controllers I'll use sendAction for now.

The session and comment is passed into the component. We can use it to check if the user is logged in and display comments. If they are authenticated they'll be able to leave a comment. The unless and if helpers to make this possible.

Ember 2.0 has been promoting one-way-binding. What that means in our example is that the body property is copied to the template. Any changes to it won't effect the parent component's property. This actually makes a lot of sense.

One way to update the body property in the template is to attach an action to the onchange event. When any change occurs the target.value is copied to the body property. The mut helper makes the body property mutable. Once this is done the body property can then be submitted as an argument to the submitComment action in the component.

In some instances using one way bindings with native <input> elements might cause cursor problems. Check out Dockyards ember-one-way-controls addon. It fixes this and adds a lot more features.

The template is broken into two parts. The first part only displays if isEditing is true. The next section shows the post. The markdown addon is used here to convert the text in post.body to markdown. This gives us a preview of our edits while we're typing. The moment addon is also used here to display the date. Once again we'll use the <textarea> element using one-way-binding to capture the body and title.

This computed property takes the model and session objects passed in and checks to see if the username matches**. The purpose is so users can't edit other people's posts only their own. The isAllowed computed property will return true if everything matches and false if it doesn't.
**This will need to be enforced on the server side to be effective

The rest of the actions use sendAction to send everything to the route. The isEditing property keeps track if the article is being edited.

This takes both the title and body and grabs the passed in save value and sends the action.

If all goes well it should look like this.

That's it for our components.

Application

When the app loads the application route will load. The application and index template will also load. In our app we want all the posts listed and clickable. Each post will link to the posts route that will display the edit-post component.

Application Templates

The application template is using bootstrap to display a simple navigation menu at the top.

In the code above the session service is used to display menu options. The login link logs the user in while the logout link logs the user out. Just for fun I added the current logged in users profile as a picture at the top that links to their Twitter profile.

The index template will render inside the application's outlet. This is where each post will be displayed. The each helper iterates over each post. This is also where we use the excerpt helper we created earlier.

Notice how each post is linked to the titleURL, not the id? This is so we can have better looking URLs. The titleURL will get passed to the posts route so it can lookup the correct post and return the model.

The route is responsible for returning the model and handling actions. In this example the model returns all the posts in the database.

The login and logout actions use the session service. To login we call open and give it the name of the provider. In this case Twitter. To logout all we need to do is call close.

In the future I'd like to update the application so the user is saved after a successful login. In addition a failed login should prompt the user. This isn't implemented yet either although it would be easy to add. As of now the user will be created later when they create a comment or a new post and a failed login isn't handled. This is fine for this tutorial.

Displaying and Editing Posts

The editing and displaying of individual posts is left up to the posts route. It uses the edit-post component to display the template and handle some basic logic. The posts route is responsible for communication with Firebase.

Posts Template

This posts template displays the edit-post component. The component by design is isolated so we must pass in the session and model into it. This is also where we declare the name of the save, delete and createComment methods. These should match the names in the route.

The posts route is probably the most complicated code in the app. The save and delete actions are self explanatory. Let's take a look at the createComment action and how it deals with creating a one-to-many relationship using Firebase.

The first part here uses the getOrCreateUser utility we worked on earlier. It receives back an existing user model or a new one. This depends if the uid is already in the database or not. It also creates a new record for the comment.

The second part here uses promises. If the user promise resolves we first add the comment object to both the user and post. This is nessary when we are dealing with hasMany and belongsTorelationships. The next part uses chained promises to save information to the Firebase data store.

First we save the comment, then the post and finally the user data. It must be in this order. If any of them fails we rollback the attribute so it doesn't get saved in the data store.

We could do more error catching here, but for a basic example this is good enough.