<?xml version="1.0" encoding="UTF-8"?>
<essay xml:lang="en" version="5.0" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:gal="http://norman.walsh.name/rdf/gallery#" xmlns:foaf="http://xmlns.com/foaf/0.1/">
<info>
    
    
    
    
    
    
    
<title>nwalsh.com on Rails</title><biblioid class="uri">http://norman.walsh.name/2006/02/23/nwalshOnRails</biblioid>
<volumenum>9</volumenum>
<issuenum>24</issuenum>
<pubdate>2006-02-23T18:01:29-05:00</pubdate>
<date>$Date: 2006-02-23 19:34:18 -0500 (Thu, 23 Feb 2006) $</date>
<author>
      <personname>
<firstname>Norman</firstname>
	<surname>Walsh</surname>
</personname>
    </author>
<copyright>
      <year>2006</year>
      <holder>Norman Walsh</holder>
    </copyright>
<abstract>
<para>A cursory look at using the Ruby on Rails framework to publish
nwalsh.com.</para>
</abstract>
<dc:subject rdf:resource="http://norman.walsh.name/knows/taxonomy#TheWeb"/>
</info>

<epigraph>
<attribution>
      <personname>
<honorific>Sir</honorific>
	<firstname>William</firstname>
	<surname>Bragg</surname>
</personname>
    </attribution>
<para xml:id="p2">The important thing in science is not so much to obtain new
facts as to discover new ways of thinking about them.
</para>
</epigraph>

<para xml:id="p1">I have a confession. I've never used any of the
popular frameworks for constructing web sites. I've never written
a page of
<link xlink:href="http://en.wikipedia.org/wiki/PHP">PHP</link>. Or
<link xlink:href="http://en.wikipedia.org/wiki/JavaServer_Pages">JSP</link>.
Or
<link xlink:href="http://en.wikipedia.org/wiki/Active_Server_Pages">ASP</link>.
I think I've installed
<link xlink:href="http://en.wikipedia.org/wiki/Apache_Cocoon">Cocoon</link>
and
<link xlink:href="http://en.wikipedia.org/wiki/Apache_Tomcat">Tomcat</link>
once or twice, but
I never got around to using them. I've always just published baked (or
<link xlink:href="/2005/12/08/baking">mostly baked</link>)
HTML pages with maybe a few server-side includes and CGI
scripts. Rolling my own back-end for this weblog was part of the fun.
</para>

<para xml:id="p3">So I was starting to feel a little left out. Or, perhaps more
importantly, like I was missing any exposure to some pretty important
technologies. And over the past few months, the buzz about
<link xlink:href="http://en.wikipedia.org/wiki/Ruby_on_rails">Ruby
on Rails</link> had piqued my curiosity.</para>

<para xml:id="p4">Before I stared this weblog, I used to publish much more
actively on <link xlink:href="http://nwalsh.com/">nwalsh.com</link>.
Now that I don't publish there as much, I've been thinking that it
could use a bit of a face lift.</para>

<section xml:id="history">
<title>A little history</title>

<para xml:id="p5">The 
<link xlink:href="http://nwalsh.com/">nwalsh.com</link> pages are built with
a customization of DocBook called “Website”. The way Website works is that
you author all of the pages independently and then you define the navigation
by building a “layout file”. (There's some similarity to
<link xlink:href="http://en.wikipedia.org/wiki/DITA">DITA</link> map files
here, actually.)</para>

<para xml:id="p6">Having independent pages means that they can be rebuilt independently.
If I edit the XML source for the Emacs page, only the Emacs page has to
be rebuilt to bring the website up-to-date.</para>

<para xml:id="p7">Well, mostly. If you look at the site, you'll see there is
one apparently dynamic element, the menu system on the left hand side of the
pages. Although it appears to be dynamic, it's actually static on each page.
The expansion of tabs is an illusion. In reality, the layout file is used
to determine where each page appears in the hierarchy and the correct 
“view” is rendered on the page.</para>

<para xml:id="p8">This means that if you change the layout file (by adding a new page,
for example), some (and in practice,
all) of the pages have to be rebuilt. That's a drag and a dynamic
framework could fix that. (JavaScript, etc. could
fix it too, but I like the fact that the site doesn't require JavaScript,
and it's been online since way before cross-browser JavaScript support
was practical.)</para>
</section>

<section xml:id="rails">
<title>Enter Rails</title>

<para xml:id="p9">The idea of retooling
<link xlink:href="http://nwalsh.com/">nwalsh.com</link>
seemed to intersect with my interest in Rails, so I devoted
a few of hours to hacking it over the past few evenings.</para>

<para xml:id="p10">Through the magic of <command>apt-get</command>, it installed easily.
And the
<link xlink:href="http://www.onlamp.com/pub/a/onlamp/2005/01/20/rails.html">O'Reilly tutorial</link>
quickly got me into the thick of it.</para>
</section>

<section xml:id="plan">
<title>Plan of attack</title>

<para xml:id="p11">I wanted to use the Rails framework to build the navigation menu
dynamically. I decided to prototype this by using the layout file to
build a database with a couple of tables that described the
hierarchy. (I don't claim any great experience with database design,
so if I made a pig's breakfast of it, so be it. Remember, this is just
a little prototyping exercise.)</para>

<para xml:id="p12">Conceptually, I divided up the navigation into categories
(top-level entries in the navigation hierarchy), pages (second-level
entries), and sub-pages (third-level entries, of which there are a
few). Sub-pages turned out to be a bit of a
<link xlink:href="http://en.wiktionary.org/wiki/PITA">PITA</link>, so I
invented a hack: if a page has a “parent page” then it's a sub-page,
otherwise it's an ordinary page.</para>

<para xml:id="p13">Once I had the databases built, I could access them in the
Rails <methodname>show</methodname> method to build the navigation tree.</para>

<para xml:id="p14">But what about the actual content? I didn't feel like going
through the effort of actually getting that in the database, so I just
hacked the stylesheets to produce HTML that included only the real
content of the page, then I could slurp that up and dump it into the
right place.</para>
</section>

<section xml:id="implementation">
<title>Implementation</title>

<para xml:id="p15">After a little Googling around to learn enough SQL syntax to get
myself going, it didn't take long to write the stylesheet that
generated the code to build the database.</para>

<para xml:id="p16">The result looks like this:</para>

<programlisting>drop database if exists nwalshcom;
create database nwalshcom;
use nwalshcom;

create table pages (
id int(10) unsigned NOT NULL auto_increment,
category int(10) unsigned NOT NULL,
parent int(10) unsigned,
title varchar(255) NOT NULL default '',
uri varchar(255) NOT NULL default '',
primary key (id)
) engine=InnoDB default charset=latin1;

create table categories (
id int(10) unsigned NOT NULL auto_increment,
page int(10) unsigned NOT NULL,
name varchar(255) NOT NULL default '',
primary key (id)
) engine=InnoDB default charset=latin1;

insert into categories values (1,1,'HIDDEN');
insert into categories values (2,2,'Home');
insert into categories values (3,3,'DocBook');
…etc., for the rest of the categories…

insert into pages values (1,1,null,'NO PAGE','');
insert into pages values (2,2,null,'Home','index.html');
insert into pages values (3,3,null,'DocBook','docbook/index.html');
insert into pages values (4,3,null,'Pub. Model','docbook/procdiagram/index.html');
insert into pages values (5,4,null,'XML','xml/index.html');
insert into pages values (6,4,null,'XSL Lint','xml/xslint/index.html');
…
insert into pages values (10,5,null,'Presentations','docs/presentations/index.html');
insert into pages values (11,5,10,'DocTrain2005','docs/presentations/doctrain2005/index.html');
insert into pages values (12,5,10,'Extreme 2004','docs/presentations/extreme2004/index.html');
…etc., for the rest of the pages…</programlisting>

<para xml:id="p17">Then all I had to do was write a <filename>show.rhtml</filename>
file that used this. The result is about what you'd expect:</para>

<programlisting>&lt;html&gt;
&lt;head&gt;
&lt;title&gt;&lt;%= @page.title %&gt;&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;table border="1" width="100%"&gt;
&lt;tr&gt;
&lt;td align="left" valign="top" width="300"&gt;

&lt;dl&gt;
  &lt;% @categories.each do |category| %&gt;
    &lt;% if (category.id &gt; 1) %&gt;
      &lt;dt&gt;
        &lt;%= link_to category.name,
                    :controller =&gt; "page",
                    :action =&gt; "show",
                    :id =&gt; category.page %&gt;
        &lt;% if (@category_page and @page.category == category.id) %&gt;
          &lt;span&gt;*&lt;/span&gt;
        &lt;% end %&gt;
      &lt;/dt&gt;
   …</programlisting>

<para xml:id="p18">Remarkably, especially when you consider that I haven't a clue
about the
<link xlink:href="http://en.wikipedia.org/wiki/Ruby_programming_language">Ruby</link>
programming language, it came together pretty quickly
(not counting a bit of fumbling with some corner cases and off-by-one
errors).</para>

<mediaobject role="flickr">
      <!--nwalsh.com on rails-->
  <imageobject xlink:href="http://www.flickr.com/photos/ndw/103247205/">
    <imagedata fileref="http://static.flickr.com/37/103247205_3b1d647303.jpg"/>
  </imageobject>
</mediaobject>

<para xml:id="p19">That's pretty obviously just a shell, but the navigation on that
page really is dynamic.</para>

</section>

<section xml:id="uris">
<title>Those pesky URIs</title>

<para xml:id="p20">One obvious problem in doing something like this is dealing with all
the current URIs. Turning all of the pages into things like
<uri>http://nwalsh.com/page/show/10</uri> might be fully functional, but it
sure isn't very pretty.</para>

<para xml:id="p21">I imagined that I'd simply have to setup a bunch of redirects or
URI rewrites in the server's <filename>.htaccess</filename> file and
live with the consequences.</para>

<para xml:id="p22">Not so! Ruby on Rails has this marvelous facility called routing
which allows you to establish the URIs that you want to use. That just
transparently turns all the controller/action/id URIs into something
reasonable.
</para>

<para xml:id="p23">Doubly cool was the fact that I could generate the correct
routing table from the existing layout file. That produced something
like this:</para>

<programlisting>ActionController::Routing::Routes.draw do |map|
  # Custom routes 

  map.connect ':index',
              :controller =&gt; 'page',
              :action =&gt; 'show',
              :id =&gt; '2',
              :index =&gt; nil,
              :requirements =&gt; { :index =&gt; /^index.html$/ }

  map.connect 'docbook/:index',
              :controller =&gt; 'page',
              :action =&gt; 'show',
              :id =&gt; '3',
              :index =&gt; nil,
              :requirements =&gt; { :index =&gt; /^index.html$/ }

  map.connect 'docbook/procdiagram/:index',
              :controller =&gt; 'page',
              :action =&gt; 'show',
              :id =&gt; '4',
              :index =&gt; nil,
              :requirements =&gt; { :index =&gt; /^index.html$/ }

  …</programlisting>

<para xml:id="p24">It makes the URIs display “correctly” and it makes all the
current links work. Pretty sweet.</para>

</section>

<section xml:id="conclusions">
<title>Conclusions</title>

<para xml:id="p25">Considering that I started knowing nothing about Ruby,
essentially nothing about SQL, and with only the most meager
experience with any sort of framework at all, the fact that I got from
zero to working prototype in half a day, give or take, strikes me as
pretty remarkable. (I'm not sure how I feel about the fact that I still
know almost nothing about Ruby even after successfully building a
working “application”. :-)</para>

<para xml:id="p26">I'm not likely to take this project any further. I might someday
give <link xlink:href="http://nwalsh.com/">nwalsh.com</link> a face lift,
but I doubt that I'll do it with a framework like this.</para>

<para xml:id="p27">That's not an indictment of Ruby on Rails or frameworks in general.
It just seems like overkill for the task at hand. If I was building a more
dynamic site, where users were creating or changing content, I'd be
really excited about Ruby on Rails. (Hmm, maybe my
<link xlink:href="/2005/02/15/ws-wtf#witw">Where in the World</link>
service, or even the blog comments framework would benefit from a framework
approach?)</para>

<para xml:id="p28">I'm also pretty repulsed by the grotesque mess of
<filename>.rhtml</filename> files. That tangle of HTML and Ruby code
stuck between magic “<literal>&lt;%</literal>” and
“<literal>%&gt;</literal>”'s just <emphasis>feels wrong</emphasis>.
(And it's common to all the frameworks, minor syntactic differences
aside, as far as I can tell.)
Not that I have a better suggestion just at the moment.</para>

<para xml:id="p29">If you need a framework, Ruby on Rails gets a pretty
enthusiastic “thumbs up” from me. I suppose other frameworks might as well,
but I haven't tried them.</para>

</section>

</essay>

