Home>Articles>
Ruby and the Web
Writing CGI Scripts
You can use Ruby to write CGI scripts quite easily. To have a Ruby script generate HTML output, all you need is
#!/usr/bin/env ruby
print "HTTP/1.0 200 OK\r\n"
print "Content-type: text/html\r\n\r\n"
print "<html><body>Hello World!</body></html>\r\n"
You could use Ruby's regular expression features to parse incoming query strings, look up environment variables, check tags, substitute text into templates, escape special characters, format up the HTML, and print it all out. Or, you could use class CGI.
Using cgi.rb
ClassCGI provides support for writing CGI scripts. With it, you can manipulate forms, cookies, and the environment, maintain stateful sessions, and so on. It's documented in full in the reference section beginning in the hard-copy book on page 501, but we'll take a quick look at its capabilities here.
Quoting
When dealing with URLs and HTML code, you must be careful to quote certain characters. For instance, a slash character (``/'') has special meaning in a URL, so it must be ``escaped'' if it's not part of the path name. That is, any ``/'' in the query portion of the URL will be translated to the string ``%2F'' and must be translated back to a ``/'' for you to use it. Space and ampersand are also special characters. To handle this, CGI provides the routines CGI.escape and CGI.unescape:
require 'cgi'
puts CGI.escape( "Nicholas Payton/Trumpet & Flugel Horn" )
Produces:
Nicholas+Payton%2FTrumpet+%26+Flugel+Horn
Similarly, you may want to escape HTML special characters:
require 'cgi'
puts CGI.escapeHTML( '<a href="/mp3">Click Here</a>' )
Produces:
<a href="/mp3">Click Here</a>
To get really fancy, you can decide to escape only certain elements within a string:
require 'cgi'
puts CGI.escapeElement('<hr><a href="/mp3">Click Here</a><br>','A')
Produces:
<hr><a href="/mp3">Click Here</a><br>
Here only the ``A'' tag is escaped; other tags are left alone. Each of these methods has an ``un-'' version to restore the original string.
Forms
Using classCGI gives you access to HTML query parameters in two ways. Suppose we are given a URL of /cgi-bin/lookup?player=Miles\%20Davis\&year=1958. You can access the parameters ``player'' and ``year'' using CGI#[] directly:
require 'cgi'
cgi = CGI.new
cgi['player'] # -> ["Miles Davis"]
cgi['year'] # -> ["1958"]
Or, you can retrieve all parameters as a Hash:
require 'cgi'
cgi = CGI.new
h = cgi.params
h['player'] # -> ["Miles Davis"]
Creating Forms and HTML
CGI contains a huge number of methods used to create HTML---one method per tag. In order to enable these methods, you must create a CGI object by calling CGI.new, passing in the required level of HTML. For these examples, we'll use ``html3''. To make tag nesting easier, these methods take their content as code blocks. The code blocks should return a String, which will be used as the content for the tag. For this example, we've added some gratuitous newlines to make the output fit on the page.
require "cgi"
cgi = CGI.new("html3") # add HTML generation methods
cgi.out{
cgi.html{
cgi.head{ "\n"+cgi.title{"This Is a Test"} } +
cgi.body{ "\n"+
cgi.form{"\n"+
cgi.hr +
cgi.h1 { "A Form: " } + "\n"+
cgi.textarea("get_text") +"\n"+
cgi.br +
cgi.submit
}
}
}
}
Produces:
Content-Type: text/html
Content-Length: 302
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML><HEAD>
<TITLE>This Is a Test</TITLE></HEAD><BODY>
<FORM METHOD="post" ENCTYPE="application/x-www-form-urlencoded">
<HR><H1>A Form: </H1>
<TEXTAREA COLS="70" NAME="get_text" ROWS="10"></TEXTAREA>
<BR><INPUT TYPE="submit"></FORM></BODY></HTML>
This code will produce an HTML form titled ``This Is a Test,'' followed by a horizontal rule, a level-one header, a test input area, and finally a submit button. When the submit comes back, you'll have a CGI parameter named ``get_text'' containing the text the user entered.
Cookies
You can store all kinds of interesting stuff on an unsuspecting surfer's machine using cookies. You can create a named cookie object and store a number of values in it. To send it down to the browser, set a ``cookie'' header in the call toCGI.out.
require "cgi"
cookie = CGI::Cookie.new("rubyweb", "CustID=123", "Part=ABC");
cgi = CGI.new("html3")
cgi.out( "cookie" => [cookie] ){
cgi.html{
"\nHTML content here"
}
}
Produces:
Content-Type: text/html
Content-Length: 86
Set-Cookie: rubyweb=CustID%3D123&Part%3DABC; path=
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML>
HTML content here</HTML>
The next time the user comes back to this page, you can retrieve the cookie values for CustID and Part, as shown in the HTML output.
require "cgi"
cgi = CGI.new("html3")
cgi.out{
cgi.html{
cgi.pre{
cookie = cgi.cookies["rubyweb"]
"\nCookies are\n" + cookie.value.join("\n")
}
}
}
Produces:
Content-Type: text/html
Content-Length: 111
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML><PRE>
Cookies are
CustID=123
Part=ABC</PRE></HTML>
Sessions
Cookies by themselves still need a bit of work to be useful. What we really want is a session: a persistent state for some Web surfer. Sessions are handled withCGI::Session (documented in the book beginning on page 508), which uses cookies but provides a higher-level abstraction.
require "cgi"
require "cgi/session"
cgi = CGI.new("html3")
sess = CGI::Session.new( cgi, "session_key" => "rubyweb",
"session_id" => "9650",
"new_session" => true,
"prefix" => "web-session.")
sess["CustID"] = 123
sess["Part"] = "ABC"
cgi.out{
cgi.html{
"\nHTML content here"
}
}
This will send a cookie to the user named ``rubyweb'' with a value of 9650. It will also create a disk file in $TMP/web-session.9650 with the key, value pairs for CustID and Part. When the user returns, all you need is a parameter to indicate the session id. In this example, that would be rubyweb=9650. With that value in the parameters, you'll be able to retrieve the full set of saved session data.
require "cgi"
require "cgi/session"
cgi = CGI.new("html3")
sess = CGI::Session.new( cgi, "session_key" => "rubyweb",
"prefix" => "web-session.")
cgi.out{
cgi.html{
"\nCustomer #{sess['CustID']} orders an #{sess['Part']}"
}
}












