Appalling Farrago

A blog about stuff

EmberCli, Torii Sessions
09 Feb 2015

This is the third part of a series of posts. Checkout part 1 and part 2.

currentUser

So far, we have a ember-cli application being served by divshot and a rails app providing authentication up on heroku. This is pretty sweet but we need to actually do something with the user returned by our backend. Torii comes with a built in session that we’re going to take advantage of. It’s pretty simple to extend our torii adapter to give our currentUser:

// app/torii-adapters/application.js
import Ember from "ember";
import config from "../config/environment";

export default Ember.Object.extend({
  open: function(authorization){
    return this._fetchSession({
      "github-auth-code": authorization.authorizationCode
    });
  },

  _fetchSession: function(tokenData) {
    return new Ember.RSVP.Promise(function(resolve, reject){
      Ember.$.ajax({
        url: config.jibber.sessionUrl,
        type: "POST",
        data: tokenData,
        dataType: "json",
        success: function(data) {
          localStorage.setItem("token", data.token);
          var currentUser = Ember.Object.create(data);
          Ember.run.bind(null, resolve({ "currentUser": currentUser }));
        },
        error: function(jqXHR, textStatus, errorThrown){
          Ember.run.bind(null, reject({ "message": errorThrown }));
        }
      });
    });
  }
});

The open property on our adapter needs to return a promise. Once that promise resolves, torii will merge any objects into the session object. On line 22, if the promise resolves we return a pojo with the currentUser. On line 20 we’re saving the user token to localStorage so we can use that later when we impliment fetching a session.

Let’s go ahead and update our application template to show the currentUser:


<!-- app/templates/application.hbs -->
<h2 id='title'>Welcome to Ember.js</h2>

{{#if session.currentUser}}
  Welcome {{session.currentUser.name}}
{{else}}
  {{#if session.isWorking}}
    One sec while we get you signed in...
  {{else}}
    {{error}}
    <button {{action 'signInViaGithub'}}>
      Jibber
    </button>
  {{/if}}
{{/if}}

{{outlet}}

And now when we sign in we can see the following:

torii-github-auth

Excellent! But we have a problem. If you refresh the page your sessions goes away ;_;

Fetching Sessions

Fixing this is pretty simple but requires some changes on the rails side. Let’s start by making the changes we need in ember before jumping into rails:

app/routes/application.js
import Ember from "ember";

export default Ember.Route.extend({
  activate: function() {
    this.get("session").fetch();
  },

  actions: {
    signInViaGithub: function() {
      var route = this;

      this.get("session").open("github-oauth2").then(function(authorization){
        // do the things after login, like redirect to dashboard
      }, function(error) {
        route.controller.set("error", "Could not sign you in: " + error.message);
      });
    }
  }
});

The changes to application route make sure we fetch the session when the route is activated. This should only happen once after the app boots. Now let’s add fetch to our adapter:

// app/torii-adapters/application.js
import Ember from "ember";
import config from "../config/environment";

export default Ember.Object.extend({
  fetch: function() {
    return this._fetchSession({
      "token": localStorage.getItem("token")
    });
  },

  ...
});

And that should be all we need here so let’s dive back over to the rails app to make sure we can pass a github token or our custom token to the session create action:

module V1
  class SessionsController < ApplicationController
    skip_before_action :verify_authenticity_token

    def create
      if fetch_or_create_user
        render json: user, status: :created
      else
        render nothing: true, status: :bad_request
      end
    end

    private

    def fetch_or_create_user
      if github_auth_code
        find_or_create_user_from_github
      elsif token
        User.find_by(token: token)
      end
    end

    def find_or_create_user_from_github
      github_authenticator = GithubAuthenticator.new(github_auth_code)
      user_factory = UserFactory.new(github_authenticator)
      user_factory.find_or_create_user
    end

    def token
      @_token ||= session_params[:token]
    end

    def github_auth_code
      @_github_auth_code ||= session_params[:'github-auth-code']
    end

    def session_params
      params.permit(:'github-auth-code', :token)
    end
  end
end

Now our sessions controller handles fetching old sessions! All we need to do is push up to Heroku and Divshot and see if everything works.

cd ~/development/jabber
ember build --environment=production
divshot push
cd ~/development/jibber
git push heroku master

You can checkout my version here and the source on my github: jibber jabber