Content and profile customization is a central part of any website’s success, yet implementing even basic authentication- and profile-related features can be incredibly tedious and time consuming. In recent years the various development communities have responded by implementing pluggable authentication extensions which in many cases provide all of the necessary functionality right out of the box. The Ruby community has been particularly strong in this regards, producing numerous fantastic solutions capable of not only managing users within a local database but also interacting with popular third-party user repositories such as Facebook and GitHub.
In the latest installment of this occasional series introducing the popular Ruby-based framework Sinatra, I’ll show you how to easily add user authentication capabilities to your Sinatra application (be sure to also check out previous articles which show you how to create a Sinatra-based REST API and interact with a MySQL database by way of the DataMapper ORM). To accomplish this goal, we’ll use the aptly-named sinatra-authentication Sinatra extension.
Installing and Configuring sinatra-authentication
The sinatra-authentication Sinatra extension is installable as a Ruby gem, meaning you can install it using the following command:
$ gem install sinatra-authentication
We’ll store the user profiles in a MySQL database, and interact with them using the DataMapper ORM. (If you’re not familiar with DataMapper, be sure to check out my recent article on the topic.) Additionally, we’ll use convenient flash messaging to notify the user of various events such as a successful login, so be sure to install rack-flash if you haven’t already done so.
Integrating User Authentication Features
Integrating user authentication features into your Sinatra application is incredibly easy.
require 'rubygems' require 'sinatra' require 'haml' require "dm-core" require "dm-migrations" require "digest/sha1" require 'rack-flash' require "sinatra-authentication" DataMapper.setup(:default, "mysql://webuser:secret@localhost/stampclub") DataMapper.auto_upgrade! use Rack::Session::Cookie, :secret => 'superdupersecret' use Rack::Flash
Save this file as
app.rb. For the purposes of this example I’m using a database named
stampclub. In order to follow along with the examples you’ll need to create a database and pass along the credentials to the
DataMapper.setup method as demonstrated above.
Next, create a file named
layout.haml, saving it to a directory named
views and adding the following content to it:
!!! %html %head %title Stamp Club %body = yield
views/layout.haml in place, open a terminal window and execute the following command from within your application directory to start the Sinatra server:
$ ruby -rubygems app.rb == Sinatra/1.2.6 has taken the stage on 4567 for development with backup from Mongrel
Thanks to DataMapper’s convenient schema migration capabilities, merely starting the application for the first time will result in a table named
dm_users being created within the database you specified in
mysql> describe dm_users; +------------------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------------+------------------+------+-----+---------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | email | varchar(40) | YES | UNI | NULL | | | hashed_password | varchar(50) | YES | | NULL | | | salt | varchar(50) | YES | | NULL | | | created_at | datetime | YES | | NULL | | | permission_level | int(11) | YES | | 1 | | +------------------+------------------+------+-----+---------+----------------+
In addition to creating the
dm_users table, sinatra-authentication creates a number of routes which implement the various user registration, login, logout, profile viewing, and profile editing features. If you’re familiar with REST, then these routes should make perfect sense. If you haven’t yet been acquainted with REST, check out my recent article on the topic, which shows you how to implement a REST-based API using Sinatra. In any case, sinatra-authentication generates the following routes out of the box:
GET '/login' GET '/logout' GET '/signup' GET/POST '/users' GET '/users/:id' GET/POST '/users/:id/edit' GET '/users/:id/delete'
Creating an Account
Be sure to test out the routes by navigating to
/signup and creating a new account. You’ll see sinatra-authentication’s default registration view (presented in Figure 1).
Figure 1. The Default Registration Form
After creating an account, be sure to check out the
dm_users table, where you’ll see that a new row has been created such as the following:
mysql> select * from dm_usersG *************************** 1. row *************************** id: 1 email: email@example.com hashed_password: c709816a0d6ebc500206d5d4a3495e9743cfd030 salt: 1gf8Md1Q7l created_at: 2011-10-18 16:22:03 permission_level: 1 1 row in set (0.00 sec)
Adding a Flash Message
If you started the Sinatra application from scratch, then you received an error message after pressing the registration button, despite having confirmed that the new user information was added to the
dm_user table. This is because sinatra-authentication will redirect the user to the application’s home page, which doesn’t yet exist. Open
app.rb and add the following route:
get '/' do haml :home end
Next, create a file named
home.haml, placing it in the
views directory and adding the following contents:
%h1 Welcome to the Stamp Club website = flash[:notice]
Once added, try logging out of your new account (navigate to
/logout). After being successfully logged out of your account, sinatra-authentication will redirect to you the home page where you’ll be greeted with a flash message stating
Accessing User Data
Chances are you’ll want to know whether a user is logged in so as to provide custom content. sinatra-authentication makes several global variables available which you can use for this purpose. For instance, add the following snippet to your
layout.haml file will produce a tailored message based upon whether the user is currently logged in:
- if logged_in? = "Welcome back, " + current_user.email - else <a href="/login">Login</a> | <a href="/register">Register</a>
Where to From Here?
The sinatra-authentication extension packs a pretty powerful punch while requiring minimal effort on the part of the developer. In fact, for rudimentary purposes you could conceivably use the extension without even needing to tweak its default behavior. However, chances are you’ll want to modify the default views, as well as extend the default users table. For more information about such possibilities, check out the sinatra-authentication home page.
About the Author
Jason Gilmore is founder of the publishing, training, and consulting firm WJGilmore.com. He is the author of several popular books, including “Easy PHP Websites with the Zend Framework”, “Easy PayPal with PHP”, and “Beginning PHP and MySQL, Fourth Edition”. Follow him on Twitter at @wjgilmore.