Building a Simple AJAX Website with Sinatra & jQuery
To mark AJAX's birthday on 18th March, we've put together a screencast to show you how to create your very own AJAX-updating countdown website for the big day.
What you'll learn
- How to build your own updating "Is it" website
- How to determine in Sinatra if a request is an XMLHttpRequest or not
- How to disable layouts on XHR requests in Sinatra
Welcome to a special Screencasts.org episode. March 18th marks the anniversary for when Internet Explorer 5 was released. Included in that release was the formative version of the
XMLHttpRequest API. In other words, on March 18th, it's AJAX's birthday! And what better way to celebrate than by building a website that uses AJAX to tell us if it's AJAX's birthday or not!
In this episode we'll be using Sinatra, Haml and jQuery. If you're new to any of these, we recommend you check out our introduction screencasts on these topics on Screencasts.org. They'll get you up to speed.
"Is It" Websites
You may have come across this genre of website before. They're simple websites with a "Yes" or a "No" in the middle of the page. They answer a question like "Is it Christmas?", "Is it November?" or some other time-sensitive question. Sometimes the pages also have a countdown timer.
In this episode we're going to create isitajaxsbirthday.com with a countdown timer.
Building an "Is It" website
Below this video is a zip file with the beginnings of our Sinatra application in
app.rb, with an empty
get route for the root URL. You'll notice it requires 'birthday_countdown'.
get '/' do
If we look in
BirthdayCountdown', we have several methods, but we're only going to be using the constructor,isit?
andseconds_to_go`. All the other methods are there to help these three methods, and are there for readability.
The constructor takes in two arguments,
day, which get cached as
@birthday_day. Also, for convenience, instead of repeating Time.now all the time, we cache
@year for the current date.
Cache @month, @day and @year on initialization
def initialize(month, day) @birthday_month = month @birthday_day = day
# Current date
@month = Time.now.month
@day = Time.now.day
@year = Time.now.year
isit? method ,we make sure the current month and birthday month match as well as the current day and birthday day.
Is it birthday?
def isit? @month == @birthday_month && @day == @birthday_day end ...
seconds_to_go method returns an integer of how many seconds we've got left until we celebrate. It uses one of the helper methods called
next_birthday to help us do that.
For the countdown
def seconds_to_go next_birthday.to_i - Time.now.to_i end ...
Examining our downloaded files further, we have a layout and two views: One for when it's AJAX's birthday, and one for when it's not.
In our layout, we've included jQuery already, and left some space to write our jQuery code.
OK so let's add some logic to our root URL block to show either the
:yes or the
So let's initialize a
BirthdayCountdown instance by passing it
3, 18 for the month and day.
get '/' do @countdown = BirthdayCountdown.new(3,18)
Now for the view. We need to pass in either
:no. Let's implement a method within
If it is the birthday, let's return
:no if it's not.
Returns the view needed for Sinatra to present
def to_view isit? ? :yes : :no end
Here we're using the ternary operator to reduce lines of code. This is a shorthand way of writing an
else statement. The first value will be returned if the condition is true, and the second if it's false. This is also known as an inline if or conditional operator.
Now in our
app.rb, in our
get route, we can include
get '/' do @countdown = BirthdayCountdown.new(3,18) haml @countdown.to_view end
Let's start up our application by typing
ruby -rubygems app.rb, which will automatically include rubygems. Then, let's visit http://localhost:4567 in our browser and we'll see that the code works: Since today isn't March 18th, it says "No".
As you can see from the downloaded code, there's a countdown at the bottom of our
no view. It's static at the moment, so let's write some jQuery to check if it's AJAX's birthday every second, because we just can't wait! We want to see those seconds count down!
Under the Haml
ready. Let's use the shorthand
$(). Usually your
ready function is going to be an anonymous function containing the code you want to execute. But in this case, we're going to be doing the same thing on
ready that we want to do every second, so we'll pass in the name of our function,
getUpdate, instead of writing an anonymous function.
So let's create this
getUpdate() function, and inside it, let's load the contents of the root path into the
$("body") element. Then let's set a timeout of 1000 milliseconds, or 1 second, to call the
If we refresh our browser window, we'll see the timer update. And that's it we're all done!— Well almost.
If we look in the Resources tab of the Web Inspector we see that the full page, layout and view, is sent by Sinatra when requested by the AJAX call. This may have some unwanted side effects down the road. All we want to do is send the view with no layout. To solve this we need to switch off the layout when the request is an XHR request. Sinatra allows you to query the request to see if it's an XHR request by calling
.xhr? on the
Sinatra allows you to turn off or specify layout files. This is done by setting the
false to disable the layout, or you can pass in the name of the layout as a symbol to enable it. In our case, our layout is named
layout.haml so we set the
:layout option to
get '/' do @countdown = BirthdayCountdown.new(3, 18) haml @countdown.to_view, :layout => (request.xhr? ? false : :layout) end
OK let's restart our Sinatra app, and go back to our Web Inspector. Now, we can see all the new requests only have the view part of the markup. Great.
And that's it!
We're going to post this site up at isitajaxsbirthday.com. Feel free to share it on the rub up to AJAX's birthday.
Happy Birthday AJAX! And here's to another year of developing awesome dynamic websites!
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!