Using ActiveRecord with Sinatra
In this screencast we'll create a URL shortener in Ruby with Sinatra. We're going to show you how to integrate ActiveRecord with a Sinatra application.
You'll need this regular expression to follow along:
What you'll learn
- How to integrate ActiveRecord in to Sinatra with
- How to build a URL shortener and how to use Base 62 in order to keep your urls short
Welcome to the Using ActiveRecord with Sinatra screencast. In this episode we'll show you how to build a URL shortener in Sinatra. If you're new to Sinatra, we recommend you watch our Introduction to Sinatra screencast before watching this video. We'll also be using Haml in our views, so we also recommend getting up to speed with our Introudction to Haml screencast.
ActiveRecord in Sinatra
To get Sinatra working with ActiveRecord, we could do it the long way, by configuring it all up ourselves and writing the migrations ourselves, but that would take quite a while. Thankfully, Blake Mizerany, the creator of Sinatra, has provided a gem that will get you up and running in a couple of minutes. The gem is called
sinatra-activerecord extends Sinatra to use ActiveRecord, and provides helpful
rake tasks. Currently there are two rake tasks provided. There is
db:create_migration for creating migrations, and the familiar
db:migrate for running migrations. We'll go into the setup and usage of both later in this video.
First let's get
sinatra-activerecord installed. We need to install the gems:
sqlite3 (for our database).
Now that they're installed, we need to set up our
Rakefile. To do this, let's first create our
app.rb, then we'll
require 'sinatra' and
Then, we'll make a
'sinatra/activerecord/rake', which includes
db:migrate in our list of available
So when we run
rake -T in our console, we see both tasks are now available.
Creating Our Model
Now that we've got this set up, let's create our first model
ShortenedUrl. So lets type in
rake db:create_migration and hit return. As you can see, we need to pass in a
NAME option with the name of our migration. In our case, let's pass in
As you can see, it's created a
db/migrate folder with our migration in it. Now, let's write our
down migration code.
self.up we want to create the table
:shortened_urls with the string
:url. Let's also be sure to add an index on
sinatra-activerecord doesn't have a
db:rollback task at the moment, it's always good to get in the habit of doing so. So we want to drop the table
:shortened_urls on rollback.
So when we run
rake db:migrate, you'll see the migration run fine, and it creates a
development.db database with the table
You can manually rollback by going into
'app', and then the migration path. Then, call 'down' on the migration class. In our case,
CreateshortenedUrls.down. And as you can see, the table is dropped. Let's go
up again and move on.
OK, in our
app.rb let's create our
ShortenedUrl model. This is done in our
app.rb file by typing
class ShortenedUrl, and then inheriting from
ActiveRecord::Base. We can include
validates_presence_of too, just like you'd expect in Rails.
We should also add a regular expression to validate the format of the
We found a regular expression on John Gruber's Daring Fireball blog, but we've had to tweak it a little to fit our example a bit better. We'll include it in the show notes.
So that's all we need for our model. Now, to our routes.
We'll create a
get route for our root path, for when people visit the site.
We'll also create a
post route, to create our shortened URL.
We'll also create a
get route to forward people from the shortened URL to their destination. Let's create a named parameter called
Let's assume for the time being that the
id of our saved
ShortenedUrl is the shortened version of our URL. So let's
ShortenedUrl with our
:shortened parameter, which is its
redirect to the
Now that we have our redirection code, let's add some view files.
Let's create a views folder and include a layout. We'll create a very simple, crude layout...
OK, now let's create an index view. In here, let's create a
%form that posts to the root with a
%label(for="url") [label for url] and a text%input
for the URL. Finally, we'll add asubmit` button.
Let's not forget to add
haml :index inside of our
get route block for the root path.
Now, in our
post route block, let's write the code for finding or creating our
@short_url = ShortenedUrl.find_or_create_by_url(params[:url]) will either find or create a new
@short_url.valid? is valid then we show the
:success view. If not, let's show the
OK, so let's create a
success.haml file, and in it, let's include our shortened url.
OK, so let's try it out.
As you can see, if we type in something invalid, we see the error message appear. And if we type in a valid URL, like
http://screencasts.org, we the "shortened" URL.
Let's copy and paste this address into our address bar, hit return...and as you can see, it forwards us to Screencasts.org.
Alright, so our code is working. But this isn't that much of a URL shortener since when we get to the
id of 10 our URL will increase by one character. What we can do to prevent the premature lengthening of the URL is to convert our
id into a Base 62 string. Base 62 uses letters and numbers, to write numbers with with less characters, since we have all 26 letters, upper and lower case, with the 10 digits, 0-9, all at our disposal. Twenty six uppercase letters, plus twenty six lowercase letters, plus ten numbers, equals 62. That means our URL won't increase by one character until we reach the 62nd URL. After that, our URL won't increase by one until the 3,844th URL is added, as that is 62 squared.
So using Base 62 scales well! Another benifit form using Base 62 is that since the characters are all alphanumerical, we won't have any problems with the shortened URLs.
To encode integers into Base 62 strings, we can use a gem called
alphadecimal. This gem allows you to call
.alphadecimal on integers to convert them to Base 62 strings. The reverse is also true. If you call
.alphadecimal on a string, you get an integer returned.
So let's install
alphadecimal, using the command:
sudo gem install alphadecimal.
Now let's require it in our
Let's add a
shorten method to our
ShortenedUrl where we convert the
id to a Base 62 string.
Then in our
:success view, let's change
Now, we need to create a class method on
ShortenedUrl to find it by the Base 62 string. We'll call this method
find_by_shortened. We'll pass in a string,
shortened and then convert it back to the integer,
id by calling
.alphadecimal. Then we just need to
Finally we just need to update our redirect route block, so instead of a simple
find we replace it with
And that's it. If we go back to our browser and enter a few more URLs, we see the Base 62 URLs being shown. And if we copy-and-paste them, we find that they redirect correctly too.
Thanks for watching! Subscribe to our RSS feed, follow us on Twitter, and please leave any questions, comments or suggestions for new screencasts in the comments below. If you like our videos, and think your friends, followers or colleagues would benefit from seeing them, please feel free share via any of the links below the video. We really appreciate your support.
See you next time!