Ruby-CGI Tips
Stop Error Suppression
Producing a backtrace from a script can be a security hazard, but at least in the development stage it's very nice to see the error that the Ruby interpreter spits out. This can be done by wrapping the entire script in a block and then checking for exceptions. This ensures that the return code from the interpreter is always true. So in general this is the structure of a CGI that I employ:
#!/usr/local/bin/ruby begin require "cgi" cgi = CGI.new puts "Content-type: text/html" puts puts "<html> ... </html>" rescue Exception print "Content-Type: text/plain\r\n\r\n" puts $!.inspect, $!.backtrace end
(In practice I don't actually indent this block.)
Use eRuby
It's great:
#!/usr/local/bin/ruby require "eruby" import puts "Content-type: text/html" puts title = "My first page" ERuby::import('template.rhtml')
No anything inside <% ... %> in template.rhtml is evaluated with the environment that called it.
Alias cgi-bin
I often keep CGI's in the cgi-bin folder, but I don't always deploy it that way. This what I do in Apache:
ScriptAlias /app/ "/home/eradman/public_html/cgi-bin/"
Or in thttpd a more general pattern:
cgipat=**.cgi|/cgi-bin/*|/app/*
Also in Apache there's a nice option that can be used in any virtual host entry that declares anything with executable permissions to be treated as a CGI.
XBitHack on
Use [sym]links
Hard links are slightly faster, but some versioning utilities (CVS) break the link by creating a new copy of the file. So sym-links provide a simple way to make simple URLs without complex rewrite rules. Just make sure Apache is told to use them:
Options FollowSymLinks
Now my directory listing might look something like this:
$ ls -ali | grep lrwx 2131786 lrwxr-xr-x 1 tei users 11 Mar 24 2006 customer -> customer.rb 2131628 lrwxr-xr-x 1 tei users 13 Apr 21 2006 delinquent -> delinquent.rb 2136943 lrwxr-xr-x 1 tei users 11 Apr 28 2006 deposits -> deposits.rb 2131822 lrwxr-xr-x 1 tei users 7 Mar 27 2006 main -> main.rb 2138537 lrwxr-xr-x 1 tei users 11 Jul 14 11:27 orphaned -> orphaned.rb 2135727 lrwxr-xr-x 1 tei users 11 Apr 26 2006 payments -> payments.rb 2131800 lrwxr-xr-x 1 tei users 7 Mar 24 2006 user -> user.rb
Rewrite URL's
My favorite use of mod_rewrite is to pass part of a URL as an argument to a script:
RewriteEngine on RewriteRule ^(.*)article/(.*)$ $1cgi-bin/article.rb?id=$2
Now any characters following article/ will be passed to article.rb's id parameter.
CGI Indexes
You may not realize that the Apache DirectoryIndex will accept pathnames as well as filenames, so you can use an absolute URL path to rest for a default script:
DirectoryIndex index.html /cgi-bin/index.rb
This is cool because it's a URL, not a file system path
Redirecting Output
If you need to capture the output of ERuby or the functions of another library you can assign a file handle to $stdout.
saved_stdout = $stdout begin output = File.open("report.lout","w") $stdout = output ERuby::import('report.rl') output.close end $stdout = saved_stdout
Now when ERuby::import is called print calls are written to the open file. Always save the original value of $stdout so that you can restore it after the code block is finished.