Series: User Auth

Registration Form

Published on Nov 06, 2015

In the final part of our series on hand-rolling an authentication system, we tackle the registration form- how users become a part of the system.

To do this, we copy a lot of what worked in the login system, but change some key things and put in some more robust validation.

Code

The register template is similar to the login template:

<h1>Register</h1>

<div class="field">
  <label>User Name</label>
  {{input value=userName}}
  {{display-errors errors=errors.userName showErrors=showErrors}}
</div>
<div class="field">
  <label>Password</label>
  {{input value=password type="password"}}
  {{display-errors errors=errors.password showErrors=showErrors}}
</div>
<div class="btn btn-primary" {{action 'register'}}>Register</div>

The register controller is also very similar, but the validation logic has been tightened up, along with the error-handling logic:

import Ember from 'ember';
import EmberValidations from 'ember-validations';

export default Ember.Controller.extend(EmberValidations, {
  showErrors: false,
  session: Ember.inject.service(),
  validations: {
    userName: {
      presence: true
    },
    password: {
      presence: true,
      length: {minimum: 6}
    }
  },
  actions: {
    register(){
      let {userName, password} = this.getProperties('userName', 'password');
      this.validate().then(()=>{
        return this.get("session").register(userName, password)
      }).then(()=>{
          this.get('flashMessages').success('You have signed up successfully')
          this.transitionToPreviousRoute()
      }).catch((reason)=>{
        this.set("showErrors", true)
        if(typeof(reason) === 'string'){
          this.get('flashMessages').danger(reason, {sticky: true})
        }
      })
    }
  },

  transitionToPreviousRoute(){
    var previousTransition = this.get('previousTransition');
    if (previousTransition) {
      this.set('previousTransition', null);
      previousTransition.retry();
    } else {
      // Default back to homepage
      this.transitionToRoute('index');
    }
  }

})

The register method on the session service is also similar, just to a different endpoint:

register(userName, password){
    return new Promise((resolve, reject)=>{
      Ember.$.ajax({
        method: "POST",
        url: '/users',
        data: {
          email: userName,
          password: password
        }
      }).then((data)=>{
        var token = data['authentication_token']
        var user_id = data['user_id']
        Cookies.set('userId', user_id)
        Cookies.set('authenticationToken', token)
        this.initializeFromCookie()
        resolve()
      }, (reason)=>{
        reject(`Server error: ${Ember.get(reason, 'responseJSON.error')}`)
      })
    })
  },

On the server side, I edited the POST /users endpoint:

class UsersController < ApplicationController
  before_action :authorize_user, except: [:create]

  def resource_class_name
    'user'
  end

  def create
    email = params[:email]
    password = params[:password]
    if user = User.find_by(email: email)
      render status: 400, json: {error: "A user with that email address already exists"}
    else
      user = User.create(email: email, password: password, password_confirmation: password)
      user.save
      render json: {authentication_token: user.authentication_token, user_id: user.id}
    end
  end
end

Transcript

Hello and welcome back. This is the last in our series about hand rolling your own authentication system. So previously we had authenticated routes as well as ways to login, but we don’t have a way to register a user yet. We’re going to be doing that today, and we’re going to be combining the stuff we’ve learned in the previous episodes to create something that is similar but has its own special requirements.

So first we’re going to create the register route,

and then we’ll add a link-to register if you’re not signed in.

Then we’ll need a template for our new route. We’ll go ahead and copy the login template since it’s going to be very similar, and then just change a few things so that it makes sense.

This form as well as several other things we do this episode do repeat themselves, and so are good candidates for a refactor. However, we won’t be tackling that this episode.

So this is what that gets us. Now we need to make the Register button do something.

The login controller already has functionality very similar to what we need, so we’ll copy it and change a few things like we did before, but here we’re going to have to change a few more things.

The first is that we want our validations to explicitly run before we call anything on the session. We could’ve done this on Login, and we probably should’ve, but it’s even more important now.

So the validations are a promise and then our session register is also a promise, so we’ll go ahead and stack those promises.

So we have several different promises happening here, stacked on top of each other, and they’re caught by the same catch block.

And this is generally good, except now we have the reason coming back, the error coming back, in different formats sometimes. So we’ll need to take care of that.

We’ll do this by checking the type and if it’s a string, something that’ll look nice to the user, will show a flash message. Otherwise we just take the error and assume that it’s the type that is going to show up in the template already.

Now obviously this won’t work for all situations. You need to customize this so it’s specific to what you’re expecting to be returned.

So now we have the register action in the register controller. Let’s build the register method in the session service.

Once again, we’re going to copy the login and then expand on it.

The changes here are fairly easy. So we name it register instead of login, and then instead of posting to the sessions route, we post to the users route. We could also post to a register route if we wanted to, if we made our server like that.

Finally, we make changes in our error handling.

So previously, there was always the same error,

but now we might get back multiple errors, so we have to take that into account. So we’ll get the response and then we’ll get the responseJSON and the error from that using Ember.get.

Now this screencast is mostly about the JavaScript, but let’s take a quick peek at our server method. So this is the create users method, and we’ll basically be getting the email and password. If there’s already a user with that email, then we’ll send back an error. Otherwise, we’ll create the user, save it, and then send back their authentication_token and their user_id.

You also note that although we usually do the authorize_user action before everything, we create an exception for the create method.

So now let’s see this in action. So we type a user name, and of course before it even sends off to the server, it does the validations.

So let’s get rid of those validations, and good, we’ve registered.

Now we can try to register that same one again and it’ll give us the server error.

So this is the end of our series about how to rule your own authentication method in Ember. This understanding that you’ve gained should help you in the next week or two when we explore Ember Simple Auth and Torii, and we’ll see how they can make things we’ve done easier and how they can do things that we hadn’t yet created. I’ll see you then.

User Auth

Subscribe to our mailing list