13 Jun 2010

Delving into more Ruby Syntax and Understanding Rack & Sinatra

Last time I sprinted through a huge range of technologies based around or connected with ruby:

  • heroku
  • sinatra
  • passenger
  • haml
  • sass
  • mongodb (& MongoHQ)
  • ajax

If you’re interested in those technologies, check out the last post.

I was very pleased to have got a fully working landing page live and collecting emails in a NoSQL database (check it out at Quotally.com). However, having gone through those technologies so fast I felt that I had perhaps overlooked some of the details of how these technologies were actually working and how they were slotting together.

Therefore this week I am aiming to get my head around what “Rack” is and how the Sinatra framework is working under the hood. I hope by documenting my learning that you can also learn or you can point out some parts where I am going wrong :)

Delving into more Ruby Syntax

In the first week, I had my first experiences of Ruby syntax and I was very impressed. This week I have chosen to go further into the syntax and I am using Why’s (poignant) guide to ruby.

Blocks & block arguments

Coming from PHP, blocks look somewhat familiar but seem to be written slightly differently, with the code inside the block starting right after the opening curly brace:     

1 2.times { puts "Hello World!" }

In reading around, I have in fact learned that the syntax must be done this way, and the following is not allowed although it is common to see things like it in PHP:

1 # Won't work
2 2.times
3 {
4   puts "Hello World!"
5 }

However, I see that the curly braces can also be traded for do … end. Got to love the code they come up with in Why’s poignant guide:

1 loop do
2   print "Much better." 
3   print "Ah.  More space!" 
4   print "My back was killin' me in those crab pincers." 
5 end

Block arguments are a set of variables at the start of the block, surrounded by pipe characters. I was at first, expecting this to work:

1 name = "Joel"
2 2.times { |name| puts "Hello #{name}!" }

However, the output was as follows:

1 Hello 0!
2 Hello 1!

Not quite what I was expecting :) So I have just learned that the parameters put into the blocks are not explicitly named variables which already exist but are rather parameters from the method which is calling the block. Rubyists please correct me if I’m wrong here :)

Questions for experienced Rubyists

I’d love to know what is preferred between { } and do … end – is it simply do … end for longer blocks?

I’d also love to see how you would go about changing my last bit of code to make it do what I expected, which was to print “Hello Joel!” twice.

Ranges

Funnily enough, ranges are something pretty new to me and they seem like they could be handy at times. Ranges are numbers or other characters within parenthesis with two dots or three dots in between. Two dots indicates the last value in the range is included, whereas three dots indicates it is excluded. An example:

#!ruby (1..3).each do |x|

1 puts "Hello!"
2 puts "Times said Hello: #{x}!"

end

Having seen this syntax, I went looking for similar things within PHP. I came across the range() function, which can be used as follows:

1 foreach (range(0, 12) as $number) {
2   echo $number;
3 }

Not bad, but I have to say the ruby syntax wins for me once again.

That’s enough syntax learning, let’s get onto something else.

Understanding Rack

Last time, I got a simple web application which allows people to submit their email and it be saved in a NoSQL MongoDB on MongoHQ. It was hosted on heroku, and as such I found that I needed to use “Rack”. For this reason, I managed to get Rack working and use the Sinatra framework to build the application I wanted. However, I went over this rather quickly and felt that I had not fully understood the role Rack was playing in this setup. For this reason, today I’m delving further into Rack.

What is Rack?

The first thing I wanted to know is what exactly is Rack. The obvious thing to do was go back to the Rack website and find a definition:

A Rack application is an Ruby object (not a class) that responds to call. It takes exactly one argument, the environment and returns an Array of exactly three values: The status, the headers, and the body.

This makes a lot of sense. So a Rack application is simply a Ruby object which returns an array of values.

A very simple Rack application

I then found a handy tutorial which had a few examples of Rack Middleware, the first of which was a basic Rack application:

1 use Rack::ContentLength
2 
3 app = lambda { |env| [200, { 'Content-Type' => 'text/html' }, 'Hello World'] }
4 run app

The above app can actually be run by saving the code to a file called “basic_rack.ru” and running the following in Terminal:

1 rackup basic_rack.ru -p 3000

I found another useful article, and the following I think sums up Rack nicely:

Rack is a piece of software, but it’s small, and its main purpose is to enforce an interface specification.

Now that we know that Rack is an interface specification, it makes complete sense that Heroku uses Rack as the way to specify this specification. Let’s move on to understanding Sinatra.

Understanding Sinatra

To understand Sinatra, I went back to my code for the simple application I built last time. Looking at the config.ru file we can see how Sinatra on Rack is triggered:

1 require 'hello'
2 run Sinatra::Application

Delving into the Sinatra code from GitHub, I found the Response class which is what finally delivers the application. It can be seen that this similarly returns an array with http status code, header and body:

 1 # The response object. See Rack::Response and Rack::ResponseHelpers for
 2 # more info:
 3 # http://rack.rubyforge.org/doc/classes/Rack/Response.html
 4 # http://rack.rubyforge.org/doc/classes/Rack/Response/Helpers.html
 5 class Response < Rack::Response
 6   def finish
 7     @body = block if block_given?
 8     if [204, 304].include?(status.to_i)
 9       header.delete "Content-Type"
10       [status.to_i, header.to_hash, []]
11     else
12       body = @body || []
13       body = [body] if body.respond_to? :to_str
14       if body.respond_to?(:to_ary)
15         header["Content-Length"] = body.to_ary.
16           inject(0) { |len, part| len + Rack::Utils.bytesize(part) }.to_s
17       end
18       [status.to_i, header.to_hash, body]
19     end
20   end
21 end

I decided at this point that it was not worth looking through more of the code: what would rather be more useful is a discussion of the suitable applications of Sinatra over other Ruby frameworks. This is particularly relevant right now since the “coming soon” page to collect interested people’s emails has been built and I am now looking to start work on the full application.

The difference between Sinatra and Ruby frameworks

Sinatra is not a Model-View-Controller (MVC) based framework for creating websites. It is rather a simple yet powerful Domain Specific Language for creating RESTful applications by defining actions and how the application will resond to them.

To remind ourselves, let’s look at a very simple Sinatra application:

1 require 'rubygems'
2 require 'sinatra'
3 
4 get '/' do
5  "Hello world"
6 end

As can be seen, the code is minimal, and the entire web application could easily be deployed as a single file.

What should Sinatra be used for?

I think an article I came across answered this pretty well:

API implementations, quick minimal applications, and web development that does not want or need things that are included in Rails, like ActiveRecord. Control panel mini-applications, or perhaps widgets.

Taking a look at some of the responses of Rubyists using Sinatra, here are some other insights:

In general, Sinatra is just fun to use as it provides the most direct and clean route to get an idea or a piece of code on the web.

I always reach for Sinatra when I want to prototype an idea. It’s easy to get something in place so I can iterate on the idea quickly. Sinatra is great for deploying prototypes too!

Sinatra is a great tool to accomplish small tasks as a minimal layer on top of http protocol.

Sinatra’s lean DSL encourages me to produce similarly beautiful code. Sinatra never gets in my way. Sinatra goes out of its way to make my life simple.

Sinatra lets you create REST based services with minimalistic approach which is ideal of mobile back ends.

So it seems that most people agree it’s great for small applications, prototyping or for creating an API. That gives me an idea…

Combining Sinatra and a framework such as Rails by using API-driven development

This idea is one I’ve been a fan of for a while, and I actually put it into practice at OnePage, though that is written in PHP.

The idea is to build the API for your application right from the offset, and build your web app to be the first application which makes use of your API. By creating your API and your web app alongside each other, I believe there are at least three immediate advantages:

  • The methodology naturally separates code and should improve code quality
  • If your own app uses your API, then it’s going to have to be solid
  • This method allows high agility, since you can release your public API almost instantly at any point in time

I have spoken to some people and it is a concept which can be hard to get your head around, but having played with Sinatra and also wanting to experience a more substantial Ruby framework such as Rails or Merb, this seems like a perfect way forward which will still give me the experience of the Ruby language whilst working with Sinatra and also the magic and opportunity to discover the reason for the hype around a framework such as Rails.

What do you think of this approach? I would love your comments.

Next time

Next time I plan to reveal more about the specific application I’m building in order to learn Ruby, and I will be looking into more syntax in addition to assessing the various frameworks out there. Do you think it’s too soon to delve into a framework? Let me know your thoughts.

Please comment :)

The reason I am doing this blog is that hopefully by documenting my journey from PHP to Ruby the information can be useful to others, whether starting Ruby from scratch, coming from another language or even those experienced in Ruby. In addition to this, a side-effect is that it really accelerates my learning of the language due to experienced folks chiming in with their comments and insights. Please comment and let me know how I can improve, or simply what you thought or would like me to blog about next time :)

Just before I finish, please help me decide how to format my code snippets from now on:

Useful links

Some useful links I came across in this session:

Feel free to keep up with my Ruby Delicious Bookmarks too.

30 May 2010

All in a day's work: heroku, sinatra, passenger, haml, sass, mongodb and a touch of AJAX

Well, I’ve certainly had a packed day of the Ruby learning today. Now I’m going to write it up in hopefully a more structured manner than I actually carried it out! Last week I went for the basic syntax, and I learned quite a lot. This week however, I wanted to just get stuck in and get an initial landing page up for the idea I’m using as my way to learn Ruby. Once the landing page was up in order to collect emails from those interested in trying out the service I’m building, I could slow down again and go back and make sure I understand everything. So I had my work cut out.

What I achieved

  • Set up hosting on heroku
  • Linked domain name with heroku
  • Used Sinatra to quickly get going
  • Set up local development environment using passenger
  • Delved into HAML & SASS
  • Used mongdb with heroku using the mongodb ruby driver & MongoHQ
  • Got a landing page up on Quotally.com to collect emails and save them to mongo
  • Added a little AJAX

Setting up hosting on heroku

The first thing I did was to get a local directory linked up to hosting on heroku. Heroku was always in mind as a great choice for the hosting, and part of my plan for this learning process is to not spend a penny, so I went ahead and signed up to heroku.

Linked domain name with heroku

First step was to configure my domain name (which I got free from Gandi during their anniversary offer), to the heroku app I’d configured.

I went into Heroku and saw that they need you to add 3 separate A Records for domains, so I went into Gandi and did this. I also already have the gandi domain set up for GMail so using A records was ideal rather than nameservers, though I’m not sure that possibility exists.

What is Rack?

After trying to push my simple ruby script to heroku and it being rejected, I realised that the Ruby app needed to be either Rails or Rack-based. Except I had no clue what Rack was, so I went to find out.

It turns out Rack is “a minimal interface between webservers supporting Ruby and Ruby frameworks”. Well, if I need to be using Rack then I decided that I may as well use a framework, however I wanted to use a minimal framework in order to maximise my learning of the Ruby language.

Used Sinatra to quickly get going

Sinatra had already been suggested to me in the comments of the last two posts, so I went to take a look at the framework. With their claim that it is as simple as:

1 require 'rubygems'
2 require 'sinatra'
3 get 'hi' do
4   "Hello World!"
5 end

I thought it was certainly worth a shot. How much simpler could a framework get? This was perfect, since as I said, I wanted to maximise my learning of the framework and not let the magic of a framework blur line between framework and the Ruby language itself.

With a file named config.ru:

1 require 'hello'
2 run Sinatra::Application

And a ruby file named hello.rb:

1 require 'sinatra'
2 get '/' do
3   "Hello World!"
4 end

I was up live on heroku with my first externally hosted Ruby app :) I must say, I am very impressed by the combination of ruby, git, heroku & sinatra. It made things very straightforward.

Set up local development environment using passenger

After having a local PHP setup for quite some time, I was very keen to get Ruby set up locally so I could work on the website without pushing changes to heroku every time.

For this I came across Passenger which provides easy and robust deployment of Ruby on Rails applications on Apache and Nginx webservers, which supports other frameworks (so Sinatra) via Rack. Setting it up was as simple as they make it seem, and if I wasn’t before I am now completely converted to ubuntu :)

So, after setting up Passenger and changing my hosts file, I had my local development environment all up and running.

Delving into HAML & SASS

I decided that since I was learning a new language, I may as well learn Haml and Sass, since I’ve heard them raved about my my good friend Ashley Moran, and I’ve seen it in action too and it seems to reduce repetition in code.

Haml

In order to get HAML working within Sinatra, I found this article on “Using Haml with Sinatra” and it was actually very simple:

1 require 'sinatra'
2 require 'haml'
3 get '/' do
4   haml :index
5 end

With this bit of code, and placing a file named index.haml into a directory named “views”, I could render some HTML using Haml. Here is an example of some Haml:

1 !!! XML
2 !!! Strict
3 %html{html_attrs}
4   %head
5     %title Quotally - The remarkable new way to save and share quotes
6   %body
7     %h1 Quotally

Even just after a little experience with Haml, I’m finding it a nice markup language which really follows DRY principles.

Sass

To get Sass working, it was almost as straightforward.

Firstly, point to a stylesheet inside Haml:

1 !!! XML
2 !!! Strict
3 %html{html_attrs}
4   %head
5     %title Quotally - The remarkable new way to save and share quotes
6     %link{:rel => "stylesheet", :href => "/style.css", :type => "text/css", :media => "all"}
7   %body
8     %h1 Quotally

Then, within Sinatra, use Sass for the stylesheet:

#!ruby

 1 require 'sinatra'
 2 require 'haml'
 3 require 'sass'
 4 
 5 get '/' do
 6   haml :index
 7 end
 8 
 9 get '/style.css'
10   content_type 'text/css', :charset => 'utf-8'
11   sass :style
12 end

I found that the following from the Sinatra website didn’t work for me:

1 get '/stylesheet.css' do
2   header 'Content-Type' => 'text/css; charset=utf-8'
3   sass :stylesheet
4 end

I found an error in my apache error.log which said that the header method was unknown. If you know why this wasn’t working, please let me know!

Finally, create the file named style.sass and place it inside the “views” directory which index.haml is inside. Here is some example Sass:

 1 body
 2   color: #000
 3   background-color: #D900FF
 4   font-family: 'Lucida Grande', sans-serif
 5   text-align: center
 6 
 7 a
 8   color: #D900FF
 9   text-decoration: underline
10   &:hover
11     text-decoration: none

It is rather nice, since the nesting means you can avoid repetition.

Using mongodb with heroku using the mongodb ruby driver & MongoHQ

For a while now, I have been desperate to try out MongoDB. Why? My attraction to it was mainly due to the schemaless nature of MongoDB and other NoSQL databases. This means you can avoid database migrations, amongst other advantages. Check out their website for the full list.

So, as if I haven’t learned enough new stuff already, I chose to jump into MongoDB.

MongoHQ

MongoHQ is a hosted MongoDB service. Since with heroku I don’t have full root access to the server, I am going to have to use a hosted solution. Luckily, I wanted to try out MongoHQ too, and they have a free version. So, we’re still on zero cash spent on Quotally :)

Signing up to the service is very straightforward, and then you go ahead and create a database, and a collection (think table).

Mongo Ruby Driver

I wanted to keep things simple, so rather than looking into Mongo Mapper, I went for the Ruby Driver. In the next section I’ll show you how simple the code is.

Mongo on heroku

I found that on heroku, you need to use a Gem Manifest file in order to tell heroku that extra gems are needed. Simply a file named “.gems” with the gems on separate lines:

1 bson_ext
2 mongo

Heroku was giving me problems until I included the bson_ext gem as well as mongo.

Getting the landing page up on Quotally.com to collect emails and save them to mongo

To collect emails, the form on the page needs to take email as a POST parameter and save the email to MongoDB.

The final code for the page is as follows:

 1 require 'sinatra'
 2 require 'haml'
 3 require 'sass'
 4 require 'uri'
 5 require 'mongo'
 6 
 7 
 8 get '/' do
 9   haml :index
10 end
11 
12 get '/style.css' do
13   content_type 'text/css', :charset => 'utf-8'
14   sass :style
15 end
16 
17 post '/notify' do
18   email = params[:email]
19   db = Mongo::Connection.new("mongohq-url", port).db("database")
20   auth = db.authenticate("username", "password")
21   coll = db.collection("emails")
22   doc = {"email" => email}
23   coll.insert(doc)
24   if request.xhr?
25     "true"
26   else
27     "Thanks! We've got your email and will be in touch as soon as we're ready :)"
28   end
29 end

Sinatra makes this beautiful. I have to say though at this point that I’m going to probably need to go back at some point and work out exactly how Sinatra works. If you know, I’d love to hear it explained.

So we simply grab he email from the POST parameter, connect to mongo, authenticate and then save the document containing the email (a hash) to the emails collection.

You’ll notice at the end there that if the request comes in via AJAX we simply output “true” otherwise we output a thank-you message. This is for a final touch of AJAX to finish off for today.

I am aware that more error checking should be done at this point :)

Adding a touch of AJAX

As a little bit of added fun, I chose to add a touch of AJAX. The JavaScript (using jQuery) simply catches the submit event of the form and submits the request via AJAX and shows the thank-you message in line in the page, replacing the text box and submit button rather than refreshing the page. The JavaScript is simple:

 1 $(document).ready(function(){
 2 
 3   $('input[type=text]').jgTextHint();
 4   $("form").submit(function(e){
 5     e.preventDefault();
 6     $.post("/notify", {"email" : $("#email").val()}, function(json){
 7       if(json == true) {
 8         $("form p#email_p").html("Thanks! We'll be in touch");
 9       }
10     }, "json");
11   });
12 
13 });

I also made use of a tiny jQuery plugin I developed called jgTextHint which hides the value of a text field when you click it.

That’s all, folks

Wow, I got through quite a lot, and a serious number of technologies too! See the finished landing page at http://quotally.com and please sign up to be a beta tester :)

Feedback, please!

I would love your feedback, comments and tips on what I should be doing differently. The purpose of this blog is for me to share what I’m doing so that I can learn more and get advice from the experts out there, as well as hopefully help some aspiring ruby beginners like myself. Thanks everyone!

Useful links

Some useful links I came across in this session:

Feel free to keep up with my Ruby Delicious Bookmarks too.

23 May 2010

Foray into Ruby Syntax

  Today, I decided to dive into Ruby syntax and have a play around. I took note of a few reflections in terms of similarities and differences with programming languages I am very familiar with: in particular JavaScript and PHP.

Interactive Ruby

Making use of the Ruby in Twenty Minutes article on the Ruby website itself, I was immediately introduced to "Interactive Ruby", which is fired up in the Terminal simply by typing "irb". I then used Interactive Ruby to do the classic "Hello World" in Ruby:

I also had a play with a some maths handling, but this is very basic stuff!

Let's move into actual files, and my first method!

I then decided it was time to move to actually running ruby from files. In addition to this, I made my first method - to simply say Hello, taking someone's name as a parameter:

Wait a minute, what is that crazy # and curly braces? Right, so that's the Ruby way to do string interpolation. In PHP it would be as follows:

Whilst the Ruby way to do string interpolation may seem a little more complex, I do like the Ruby syntax already. It reads nicer, and I say good riddance to semicolons and curly braces!

Let me play with loops and hashes, I heard they are neat..

The next step was to play around with loops and hashes, since I was told on Twitter that they are particularly neat in Ruby.

So, here we go! Let's make it loop through and say hello to other people as well as me :)

Now this is getting tasty! I love the syntax for looping through a hash. This feels very much like JavaScript for me, the closures (lambda functions) and .each is very much like jQuery's $.each(function(i, item){}), not to mention that it is treating names as an object which is also like JavaScript.

Bang methods and question mark methods

This part is very interesting. It seems, that whilst method names (which can include ! and ?) containing ! (bang methods) and ? have no special meaning to the Ruby interpreter, the convention is that using the ! means it is "transforming" parameters and the question mark means that it is answering the question posed by the function name (e.g. empty?). This makes a lot of sense! Yet again, it seems like a very human-friendly, readable way to lay things out.

Deserves a mention: "Why's (Poignant) Guide to Ruby"

This book is awesome! Available online here, it teaches Ruby in a beautiful way, and it makes you fall in love with the Ruby syntax. Big thanks to Neil Brewitt for the tip!

Variables - different to most languages!

Whilst, like PHP, Ruby is dynamically typed, it seems Ruby deals with variables quite differently to many different languages. They have different ways to write variables based on their scoping. So you end up with local variables, instance variables, class variables, global variables, constants and symbols all written in different ways. I guess it kind of makes sense to make them instantly recognisable, but this is new to me :) I guess it eliminates keywords like "global" too?

Symbols were a little confusing to me at first, but it seems that it simply saves memory by not creating multiple instances of words which are used over and over again. Can you gurus confirm that's the case? This article helped clarify things.

Useful articles to get acquainted with the syntax & basics

There is certainly much more for me to get to grips with yet, but I feel like I am becoming familiar and starting to enjoy the syntax already. Here are the articles I went through and am still getting through in order to pick up the basics:

How am I doing?

That's all for this time. In the next session I aim to introduce the use case I have for learning Ruby, and get a real use case coded :) Did I miss anything or not quite understand something? Please tell me how I'm doing!
18 May 2010

From PHP to Ruby, join me on my journey!

  Hello :)
 
So it's hard not to notice the attention Ruby is getting right now, especially due to Ruby on Rails. It seems like it's what all the cool kids are doing, and of course I want to be a cool kid. So having thought about it for a number of months I'm taking the plunge and getting my feet wet with Ruby. I asked you guys on Twitter if you'd like to see me blog about the process, and many of you did. So you asked for it!
 
A little background: I'm a long-time PHP developer, and I work primarily with CodeIgniter. My startup OnePage is built on top of CodeIgniter. I'm also confident with XHTML, CSS and JavaScript and get by with design by keeping it simple. Therefore I'm very comfortable with MVC, and it makes sense to try out Ruby on Rails.
 
Rather than learn Ruby for the sake of learning it, I have a specific little project I'm going to build in order to put what I learn into practice: Quotally. I think this will be a much more effective way to learn a new language, and Quotally is an idea I've been wanting to see happen for a long time.
 
The plan: short and sweet little posts updating you guys on my journey.
 
I'd love you to join me if you're also a PHP (or other) developer thinking about trying Ruby (why not do the same?), or a Ruby ninja who can scream at me when I do silly things :)
 
Join me in the comments!

Joel Gascoigne's Posterous

Hi, I'm Co-Founder of OnePage (http://myOnePage.com).

I have 3 blogs, so take your pick (hint: subscribe to all of them):

Thoughts and discoveries - Short snippets of information (quotes, videos, images) I find on the web which will be useful to entrepreneurs and Internet startups.

Technology applied to entrepreneurship - Here I aim to write more lengthy posts less frequently on subjects of interest to myself and the industry I am in rather than sharing information I find on the web.

New To Ruby - An open journal of my experience of learning Ruby and Ruby on Rails, coming from a PHP developer background.

I'm a graduate of Masters in Computing Systems at the University of Warwick and I love drum n bass and freestyle skiing :)

Say hi :)