This post outlines how to get database driven, session based user registration, authentication and login working with Ramaze and Sequel.
Introduction
Ramaze is, in my opinion, the leading Ruby web framework. Whilst the documentation and community examples are still gaining momentum, you can really benefit by spending some time learning the framework.
This post is a guide to getting user registration and authentication working. We are talking proper, database driven, session based authentication - not just a single secure login area.
Requirements
This guide is written based on Ramaze 2009.06 and Sequel 3.2.0 - earlier versions of both of these will work, but you will need the "Innated" version of Ramaze (something after 2009.05 would be best) and ideally Sequel 3.1.0. (Sequel is the database abstraction/ORM library, so you can be using SQLite, MySQL, Pg - whatever floats your database boat)
Getting started
We will be creating and editing several files - one Sequel-based database model, two controllers and a couple of view files. To save you some effort, I have provided a basic SQL schema for creating the user table.
N.B. this is a SQLite formatted query.
We also need to make sure the Ramaze application is using Sequel, and we connect Sequel to the database with the above table. In this example, I have created tutorial.db3 with the above table.
In app.rb, add in the following lines:
The controller
The controller, as you probably know, ties the interface (view) and database (model) together, we don't actually need to do much with regards to controller editing, as Ramaze has pretty sophisticated helpers for managing user logins.
With a new Ramaze project (ramaze --create my-project
), open the controller/init.rb file and make it look like this:
Important things to note are the inclusion of the :user helper; you can read up on this built-in helper here.
As a final step, we need to add two methods to controller/main.rb - this will handle the login and registration process:
And whilst we're at it, we might as well add in the very, very basic logout action:
The model
We need to define several model-level methods to help register, authenticate and login users. This will model will be a representation of the users table that you should have created in the first step.
Create a file, "user.rb", in model/, and you can make it look something like this:
Some interesting things to note...
We have user defined attributes for the password and password_confirmation fields - we do not store these in the database, but we need to assign and access them to verify the password and then hash it
The password is hashed by using SHA1, with a seed/key determined from the user password and another user-specific value stored as the salt. This means that each password is hashed differently, making things a bit more secure.
There is a bit of overlap between login and email here, as there will be in the following sections. I have chosen to demonstrate logging in with an email address, not a login name.
Don't forget...
You need to edit model/init.rb to require the model you just created.
The views
We will need to create two views, in addition to the default views that Ramaze creates for you. (Remember, a view is the webpage/interface that you actually see in the browser)
The login form
Create login.xhtml in view/, and use the following as a guide:
Believe it or not, we have nearly finished adding in user authentication; the final steps being the ability to register, and securing parts of your application.
The registration form
It is more than likely that you will want a slightly more exotic registration than the one below, but it provides a good starting point. This code should go in view/register.xhtml:
Securing actions, accessing the logged in user
There are a couple of ways you can secure actions from within Ramaze - one of which you can see in the login method above. These techniques are:
Which will redirect the user to the login page. Alternatively, you can do a "manual" check to see if the user is logged in:
Who is logged in?
It can be very useful to access information about the logged in user; if we use an example whereby a user wants to edit their comment on a blog...
This hypothetical snippet would ask the user to login first, then it would check to see if the comment exists. Finally it will check the user object to see if the ID lines up with the owner of the comment.
It is worth noting that user is accessible throughout almost all of the Ramaze application, so you can do checks within layouts, views, controllers (but not models).
Questions/problems?
Feel free to leave me a comment below with any issues you're having with the above, or if you have some improvements that can be made.