If you're a PHP developer that's starting to fall in love with ruby (like me),
you'll want to know how to write "PHP-style" web applications in ruby, for small
web apps that don't need the complexity of Ruby on Rails. You want:
- No per-app configuration necessary. Installing the app is as simple as
uploading the script files.
- Each ruby file you upload is an independent web page, e.g.
http://example.com/foo.rhtml.
- Scripts are HTML with ruby code inside delimiters (like php's <?php and ?>).
- Scripts have easy access to GET and POST data, as well as HTTP headers and
cookies.
- Scripts can easily send headers, set cookies, etc.
Unfortunately, to get this working on Debian Squeeze, some initial configuration
required, but it's a one time thing and quick in comparison to the per-app
configuration required by RoR.
First, install mod_ruby:
apt-get install libapache2-mod-ruby
Second, add the following to your site's configuration and read the embedded
comments. Note that in order to lower the ruby safe level with the RubySafeLevel
directive (default is 1), it must appear outside any "files", "directory", and
"virtualhost" blocks. If not, you will get an error like: mod_ruby: can't
decrease RubySafeLevel.
<IfModule mod_ruby.c>
RubyRequire apache/ruby-run
RubyRequire apache/eruby-run
# Safe level 1 does taint checking, but also won't let you run .rb scripts
# from a world-writable folder. I highly recommend keeping this at 1, but
# in a development environment, you can change it to 0 to make scripts
# run from world-writable folders (OTOH, you really DO want to develop with
# taint checking turned on).
RubySafeLevel 1
# Override the mime types in /etc/mime.types so the output of the script
# is displayed in the browser, not sent as a download. Some guides will
# tell you to comment out the corresponding entries in /etc/mime.types, but
# don't do that as it will affect the entire system, not just apache.
AddType text/html .rb
AddType text/html .rbx
AddType text/html .rhtml
# NOTE: To make .rb files execute, you will need to add:
# Options +ExecCGI
# to the <Directory> they are in. You DON'T need to do this for .rhtml.
<Files *.rb>
SetHandler ruby-object
RubyHandler Apache::RubyRun.instance
</Files>
<Files *.rbx>
SetHandler ruby-object
RubyHandler Apache::RubyRun.instance
</Files>
<Files *.rhtml>
SetHandler ruby-object
RubyHandler Apache::ERubyRun.instance
</Files>
</IfModule>
Now, .rhtml files will work like PHP files:
<html>
<head>
<title>Hello, world!</title>
</head>
<body>
Even numbers less than 100:
<ul>
<%
1.upto(99) do |x|
puts "<li>#{x}</li>" if x % 2 == 0
end
%>
</ul>
<%
1.upto(50) do |x|
%>
This text repeats <b>50</b> times! <br />
<%
end
%>
</body>
</html>
And .rb files will work like CGIs:
#!/usr/bin/ruby
puts "<ul>"
300.times do
puts "<li>Some text!</li>"
end
puts "</ul>"
In both types of script, you can use Apache.request to read GET and POST
data, set cookies, etc.
<html>
<head>
<title>Hello, world!</title>
</head>
<body>
GET data in rhtml mod_ruby!
<%
Apache.request.paramtable['count'].to_i.times do |n|
puts n
end
%>
</body>
</html>
Why?
Writing this post made me realize I'm trying to make ruby do something it
doesn't (yet) do well. PHP has so many built-in features for doing web stuff
like htmlentities, built-in mysql access, and easy access to GET and POST data
through $_GET and $_POST (note that Apache.request.paramtable includes both GET
and POST data, which is bad for security), so for now, I think I'll stick with
PHP until there's a better zero-config lightweight ruby web framework. Sinatra
is the best I have seen so far, but configuring it with Apache is still far too
complicated, in my opinion.