Error Handling in the Login Form

This post is a follow on from the Creating a login form with Ruby on Rails post. At the end of that post we had a login form to enter your Basecamp username and password, but it didn't cope very well if you typed in the wrong username or password. In this post we're going to handle this by displaying a message on the form saying the username or password is incorrect, and giving the user another go at logging on.

Unfortunately this will be my last post on Basecamp/Rails integration, as I'm no longer working on this project.

If we look at the error message we get when the login details are incorrect, we see a couple of things:

File does not exist: HTTP Basic: Access denied.
app/controllers/logins_controller.rb:5:in `create'

There is actually a lot more there, but this is the important stuff, the error message and where the error occurred. The error is occurring in the Basecamp.get_token line, so we need to handle this using the Ruby exception handling, i.e. a rescue clause.

Putting this into app/controllers/logins_controller.rb we end up with:

begin
    session[:token] = Basecamp.get_token
rescue Exception => e
    flash[:error] = e.message
    redirect_to new_login_path
else
    redirect_to session[:original_url]
end

If the Basecamp.get_token method gets an error, then everything between the rescue and the else will be executed. If all is OK, everything between the else and the end is executed.

In the error handling code we do two things, first set flash[:error] to the error message, and then redirect back to the login form, i.e. new_login_url. So what's this flash thing.

The Flash

The flash hash is actually similar to the session hash I described in the post on creating the login form, i.e. it is used to hold information between browser requests. There is however one difference between flash and session, the contents of flash are only held until the next request, after which it is automatically deleted.

A common use of the flash is for passing errors messages from one request to the next, which is what we are doing here. In the controller we set flash[:error] to the error message. Then in the view for the login form (i.e. app/views/login/new.html.erb) we can add a line to display the error, as shown below:

<%= form_tag :action => :create do %>
    <%= label_tag :user, 'Username: ' %><br>
    <%= text_field_tag :user %><br>
    <%= label_tag :password, 'Password: ' %><br>
    <%= password_field_tag :password %><br>
    <%= submit_tag 'Login' %>
<% end %>

<%= flash[:error] %>

A More Helpful Error Message

Finally, let's make the error message a bit more friendly.

begin
    session[:token] = Basecamp.get_token
rescue Exception => e
    flash[:error] = e.message
    flash[:error] = 'Incorrect username or password' if flash[:error].match(/Access denied/)
    redirect_to new_login_url
else
    redirect_to session[:original_url]
end