<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ramblings &#187; Programming</title>
	<atom:link href="http://ramblings.gibberishcode.net/archives/category/programming/feed" rel="self" type="application/rss+xml" />
	<link>http://ramblings.gibberishcode.net</link>
	<description>about fetching, interpreting, and executing.</description>
	<lastBuildDate>Sat, 01 May 2010 19:19:27 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Getting Ruby to talk to MSDE</title>
		<link>http://ramblings.gibberishcode.net/archives/getting-ruby-to-talk-to-msde/22</link>
		<comments>http://ramblings.gibberishcode.net/archives/getting-ruby-to-talk-to-msde/22#comments</comments>
		<pubDate>Fri, 09 Apr 2010 01:07:45 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Configuration]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Ruby Language]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Setups]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=22</guid>
		<description><![CDATA[Getting Ruby to talk to Microsoft SQL Server 2005 is one thing.  Getting Ruby to talk to Microsoft SQL Server Developer Edition 2000, has one twist that threw me off for hours.  Here, I&#8217;ll show you how to do and hopefully save you lots of frustration and brain damage from banging your head [...]]]></description>
			<content:encoded><![CDATA[<p>Getting Ruby to talk to Microsoft SQL Server 2005 is one thing.  Getting Ruby to talk to Microsoft SQL Server Developer Edition 2000, has one twist that threw me off for hours.  Here, I&#8217;ll show you how to do and hopefully save you lots of frustration and brain damage from banging your head against the wall.
</p>
<p>I won&#8217;t cover a complete Ruby and Rails/Ramaze/Sinatra installation.  This post assumes you have that much down pat, so we&#8217;ll pick up the ball with installing FreeTDS, unixODBC, Ruby ODBC
</p>
<p>If you&#8217;re using Ubuntu 8.10, you can get away with installing everything from packages with the following:
</p>
<pre class="twilight">
apt-get install  unixodbc freetds-common tdsodbc \
             libodbc-ruby1.8 \
             libdbi-ruby1.8 libdbd-odbc-ruby \
             autoconf make
</pre>
<p><b>NOTE:  I wrote this article and right before publishing, attempted to replicate these results on both mac OS X and CentOS 5.  Both failed to work with the technique I thought I had all nice and worked out.  I spent several hours over many months trying to find out exactly what&#8217;s different between the packages, but never got very far with my investigations.  For a long time, it looked to me like both the ODBC packages and the FreeTDS packages need to be tweaked to properly handle [SERVER]\[DB_INSTANCE] construct that MSDE uses vs. just [SERVER] that the full-fledged SQL Server uses.</b>  This, after all, is the convention of the Windows ODBC driver and DSN definitions.  However, there&#8217;s a really simple solution that I hit upon on Actual Technologies&#8217; website that led me to a true universal solution and that&#8217;s to learn the port the INSTANCE runs on and set up the DSN specifically to that port!
</p>
<p>But beware, the above doesn&#8217;t get you all of the freetds tools, most importantly the tsql command which can help you with debugging issues before getting into the ODBC game (that is, direct TDS connections to your SQL Server).  So, to cover the most distros possible, I&#8217;ll document the &#8220;from source&#8221; approach for *nix systems and macports for Macs so you&#8217;ll find two sets of installation instructions for every step.</p>
<h2>Preparing your Environment</h2>
<p>I prefer to pull down all source packages into my local user directory under a &#8220;~/src&#8221; folder.  The instructions that follow assume you&#8217;re in this folder.  If you&#8217;re not, then please make the appropriate substitutions as you follow along.  Additionally, I configure and compile most things as a regular user then use sudo to install system-wide as a &#8220;super user.&#8221;
</p>
<h2>Install unixODBC</h2>
<p>unixODBC provides the ODBC connectivity for the TDS driver.</p>
<pre class="twilight">
wget http://www.unixodbc.org/unixODBC-2.2.14.tar.gz
tar zxfv unixODBC-2.2.14.tar.gz
cd unixODBC-2.2.14
./configure  --enable-gui=no
make
sudo make install
</pre>
<h3>On Macs</h3>
<pre class="twilight">
sudo port install unixODBC
</pre>
<h3>On CentOS</h3>
<pre class="twilight">
sudo yum install unixODBC unixODBC-devel
</pre>
<h2>Install FreeTDS</h2>
<p>FreeTDS provides the open source implementation of the protocol implemented by both Sybase and Microsoft SQL Server.
</p>
<pre class="twilight">
wget ftp://ftp.ibiblio.org/pub/Linux/ALPHA/freetds/stable/freetds-stable.tgz
tar zvxf freetds-stable.tgz
cd freetds-0.82/
sudo ./configure  --with-unixodbc=/usr/local
sudo make
sudo make install
</pre>
<h3>On Macs</h3>
<pre class="twilight">
sudo port install freetds
</pre>
<h3>On CentOS</h3>
<pre class="twilight">
sudo yum install freetds
</pre>
<h2>Install ruby-odbc</h2>
<p>The ruby-odbc package provides the ruby bindings for ODBC connectivity.
</p>
<pre class="twilight">
wget http://www.ch-werner.de/rubyodbc/ruby-odbc-0.9995.tar.gz
tar zvxf ruby-odbc-0.9995.tar.gz
cd ruby-odbc-0.9995/
ruby extconf.rb
make
sudo make install
</pre>
<h3>On Macs</h3>
<pre class="twilight">
sudo port install rb-odbc
</pre>
<h2>Install ruby DBI</h2>
<pre class="twilight">
wget http://rubyforge.org/frs/download.php/655/ruby-dbi-all-0.0.23.tar.gz
tar zvxf ruby-dbi-all-0.0.23.tar.gz
cd ruby-dbi-all
ruby setup.rb config --with=dbi,dbd_odbc
ruby setup.rb setup
sudo ruby setup.rb install
</pre>
<h2>Configure FreeTDS and ODBC</h2>
<p>If you&#8217;re connecting to either SQL Server 2000 or SQL Server 2005 Standard, Enterprise, etc., then the typical approach is to add an entry for the server to /etc/freetds/freetds.conf and then reference that entry in the /etc/odbc.ini.  Sometimes, these files get installed in /usr/local/etc.  If so, then I will usually symlink the files into /etc for convenience, so that&#8217;s what&#8217;s referenced below.
</p>
<p>My server is called &#8220;apvdbs01&#8243; (the WINS name) with an IP Address of 10.0.2.2 and the database I&#8217;m connecting to is called &#8220;test_development&#8221; while &#8220;username&#8221; and &#8220;passwd&#8221; should be substituted with an valid user account and credentials for successfully connection to the database server.
</p>
<p>
Add a server entry for your server (which I typically give same name as Windows Server) to /etc/freetds.conf, so that host points to the SQL Server address:
</p>
<pre class="twilight">
[apvdbs01]
host = 10.0.2.2
port = 1433
tds version = 7.0
</pre>
<p>TDS version 7.0 is for SQL Server 2000.  If you have SQL Server 2005, then tds version is 8.0.</p>
<pre class="twilight">
tsql –S apvdbs01 –U username –P passwd
</pre>
<p>Once you can connect directly with the TDS drivers, move on to adding the ODBC driver entries.</p>
<p>Add the FreeTDS ODBC driver by editing “/etc/odbcinst.ini” (make sure “/usr/local/lib/libtdsodbc.so” exists first):
</p>
<pre class="twilight">
[FreeTDS]
Description     = TDS driver (Sybase/MS SQL)
Driver          = /usr/lib/odbc/libtdsodbc.so
Setup           = /usr/lib/odbc/libtdsS.so
</pre>
<p>Add a new DSN to “/etc/odbc.ini”:</p>
<pre class="twilight">
[test_development]
Driver          = FreeTDS
Description     = ODBC connection via FreeTDS
Trace           = No
ServerName      = apvdbs01
Database        = test_development
</pre>
<p>So, &#8220;FreeTDS&#8221; is the driver that we gave for the lib TDS ODBC connector in the odbcinst.ini file (this allows you to install and maintain multiple versions of the libtdsodbc.so file).  We reference this driver in the odbc.ini file with the &#8220;Driver&#8221; entry and we reference the actual server data in the freetds.conf file via the &#8220;ServerName&#8221; entry.
</p>
<p>Now that you have ODBC configured for FreeTDS, test it with:</p>
<pre class="twilight">
	isql test_development username passwd
</pre>
<h2>But that doesn&#8217;t work for MSDE!</h2>
<p>The above will get you connected to a standard or enterprise SQL Server 2000/2005 installation, but does not work for an Embedded SQL Server 2000/2005 installation.  After trying many permutations, I finally came up with a configuration that actually works.  One of the key things to know about MSDE is that the MSDE server instance is in the form of &#8220;servername\instance&#8221; rather than straight up &#8220;servername&#8221; as with standard/enterprise installations.  This is known as a &#8220;named instance.&#8221;  The trick to connecting?  Find out the port the named instance is listening on and connect to that port rather than the 1433 port!</p>
<p>You can determine the port used by the instance by using the Server Network Utility in the Microsoft SQL Server program group on the Windows server where your database resides. Select the instance name from the drop down list and select TCP/IP from the list of enabled protocols. This will show you the port number for that instance.</p>
<pre class="twilight">
[test_msde2000]
Driver         = FreeTDS
Description    = ODBC connection via FreeTDS
Server         = 10.0.2.2
Database       = my_test_db
Port           = 1348
TDS_Version    = 7.0
</pre>
<p>I could then connect to the MSDE instance like so:</p>
<pre class="twilight">
isql test_msde2000 username passwd
</pre>
<h2>Test ODBC connectivity from Ruby</h2>
<p>If both tsql and isql commands work, then you&#8217;re well on your way to connecting to SQL Server via Ruby.  To test Ruby with the above ODBC configurations:</p>
<pre class="twilight">
irb
require "dbi"
dbh = DBI.connect("dbi:ODBC:test_development", "username", "passwd")
</pre>
<h2>Connecting with Sequel</h2>
<p>One of my favorite tools for connecting to SQL DBMS&#8217; is Sequel, which is maintained by Jeremy Evans.  To connect using Sequel, install the gem:
</p>
<pre class="twilight">
sudo gem install sequel
</pre>
<p>And then give this a shot:</p>
<pre class="twilight">
irb
require 'rubygems'
require 'sequel'

DB = Sequel.odbc('test_development', :db_type => 'mssql', :user => 'username', :password => 'passwd')
</pre>
<h2>References</h2>
<p>http://www.freetds.org/userguide/confirminstall.htm</p>
<p>http://www.unixodbc.org/odbcinst.html</p>
<p>http://www.actualtech.com</p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/getting-ruby-to-talk-to-msde/22/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Implementing Ruby jobs in the background</title>
		<link>http://ramblings.gibberishcode.net/archives/implementing-ruby-jobs-in-the-background/38</link>
		<comments>http://ramblings.gibberishcode.net/archives/implementing-ruby-jobs-in-the-background/38#comments</comments>
		<pubDate>Fri, 06 Nov 2009 04:40:15 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby Language]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=38</guid>
		<description><![CDATA[I needed a way to kick off a background job that was triggered by an end-user on my Ramaze-backed website and could run for almost two hours!  This article brings together all the elements to get the job done.
Preamble (a.k.a. Ramblings)
I can hear you exclaiming, &#8220;Two hours!?  Are you nuts?  You really [...]]]></description>
			<content:encoded><![CDATA[<p>I needed a way to kick off a background job that was triggered by an end-user on my Ramaze-backed website and could run for almost two hours!  This article brings together all the elements to get the job done.</p>
<h2>Preamble (a.k.a. Ramblings)</h2>
<p>I can hear you exclaiming, &#8220;Two hours!?  Are you nuts?  You really don&#8217;t want to do that on a web application,&#8221; and you would be correct; I did not.  But alas, my users wanted it and they waved money in front of my face to get it done.  What&#8217;s a poor sap like me to do but to comply?</p>
<p>So, what is this crazy task that needs to run so urgently it couldn&#8217;t wait until a midnight cronjob task to kick it off?  Well, the task is basically exporting data from the live production database to a reporting database and the users sometimes have to generate those reports as soon as humanly possible against the then current production data.  The problem is, the export process takes anywhere from 15 minutes to almost two hours, depending on how much data has changed since the last midnight run.</p>
<p>Such a long-running process is clearly outside the normal bounds of a website&#8217;s usual request/respond lifecycle and, if you&#8217;re like me and fronting your web app with Phusion&#8217;s Passenger, you&#8217;re quite at risk of Passenger&#8217;s process recycling action killing the task in mid-stream and losing your work in progress.</p>
<p>I didn&#8217;t quite know what I was going after when I started solving this problem and the main thing I could think to google for was &#8220;background jobs ruby,&#8221; which led to a rash of articles about backgrounDRB and many many rubyists complaining about its many shortcomings and creating their own spin on what, at core is known as a message queue.  Many of the articles I read just did not cover the whole scope of the problem I faced and usually had simple solutions that lived well within the boundaries of their Rails (or Ramaze) framework&#8217;s inner workings.</p>
<p>Since I had a process that was capable of consuming resources upwards of two hours, I knew I had to completely escape the bounds of the framework and do the heavy lifting without fear that the parent process&#8217; lifespan would risk the job getting terminated mid-stream.  I also didn&#8217;t need a Rails plugin because, well, I&#8217;m building a Ramaze application and those fancy plugins just aren&#8217;t much of a help to me there.</p>
<p>One of the things I&#8217;m loving about Ramaze is that its forcing me to learn the Ruby language and its also forcing me to work harder to understand the components I&#8217;m pulling together in a solution.  With Rails, I just pulled a plugin out of thin air, plugged it in and moved along.  Which is great for rapid development, but more often than not, I have found myself later in a bind after the site&#8217;s live finding out that wonderful plugin is running way too slow and not knowing a darn thing about how to fix the problem without tearing up the whole plugin with a complete rewrite (in many cases).</p>
<p>With Ramaze, I feel much closer to the language, and I&#8217;m also finding that there&#8217;s just a <em>lot of fluff</em> I flat out don&#8217;t need that the Rails framework brings along, or rather, encourages developers to toss into the soup.  On the other hand, Ramaze&#8217;s philosophical approach of squeezing every ounce of functionality out of every line of code has really pushed me towards being a better Ruby programmer and yet the same old time crunch every nearly developer faces actually forces me to get the job done with less code and with utilizing only the critical components actually necessary to get the job done.  Which amounts to a one-two knockout punch for me because the solutions I deploy are consistently rock solid and I fully understand what I just put out there end-to-end.</p>
<h2>Getting Started</h2>
<p>The full project source can be found on <a href="http://github.com/mwlang/astroid">github.com</a> and you will also find my <a href="http://github.com/mwlang/ruby-progressbar">database enhancements to ProgressBar</a> on github.com as well.</p>
<p>This project utilizes the following:</p>
<ul>
<li><a href="http://www.ruby-lang.org">Ruby Language</a></li>
<li><a href="http://ramaze.net/">Ramaze</a></li>
<li><a href="http://kr.github.com/beanstalkd/">beanstalkd</a></li>
<li><a href="http://jquery.com">JQuery</a></li>
<li>A modified version of <a href="http://0xcc.net/ruby-progressbar/">ProgressBar</a> (included in the demo source)</li>
<li>These Gems
<ul>
<li><a href="http://raa.ruby-lang.org/project/daemons/">daemons</a></li>
<li><a href="http://flori.github.com/json/">json</a></li>
<li><a href="http://beanstalk.rubyforge.org/">beanstalk-client</a></li>
</ul>
</li>
</ul>
<h2>The Players</h2>
<p>With the ramblings out of the way, its time to get to the heart of the matter at hand.  There are three players in this game:</p>
<ol>
<li><em>The trigger</em> &#8211; This is the process that starts the whole chain reaction.  In this case, the web app where the user can click a link to start the export.  In my case, that web app was built with Ramaze.</li>
<li><em>The message queue</em> &#8211; This is the middleman in the game.  He sits around and accepts the message from trigger and passes the buck to the worker.  We call him, &#8220;beanstalkd.&#8221;</li>
<li><em>The worker</em> &#8211; This is the process doing all the work.  Amazingly, Ruby was up for the task and the daemons gem is the ticket to making this work.</li>
</ol>
<p>So lets cover these in more detail&#8230;</p>
<h2>The Worker (sort of&#8230;)</h2>
<p>The worker has got to always be around to do the job whenever that job comes in, so this suggested to me that I needed a daemonized process to watch the message queue for incoming jobs.  Many solutions that I saw called for simple cronjobs running every minute or 5 minutes or whatever.  But I couldn&#8217;t fathom why I&#8217;d want to resort to such hackery.  How are you going to scale that?  What happens if two cronjob instances fire and grab the same job request?  What about if the job crashes or the server dies in mid-job?  How is it reliably restarted?  How do I ensure long-running jobs don&#8217;t pile up and consume all memory and CPU resources (e.g. every minute start processing the next big job and next thing you know, ten of &#8216;em are running when you only have the capacity to run one or two)?  Simply put: cronjob workers is brute force mentality and rife with potential pitfalls.</p>
<p>Point being, I rapidly came to understand that I needed a message queue to serialize the jobs until the workers could take the jobs and run them and guarantee the jobs run before flushing them away.  What was surprising, was the number of message queue implementations out there in the wild!  Luckily, <a href="http://kr.github.com/beanstalkd/">beanstalkd</a> existed and had a very elegant implementation and API well-suited for Ruby.  I easily installed from source to a Ubuntu server and also installed via macports on my Macbook Pro laptop AND installed the ruby client AND tested the small demos in irb all in about 30 minutes.  Sadly I can&#8217;t say the same for RabbitMQ, Starling/Workling, ApacheMQ, and others I tried in vain to get up and going with.  So, beanstalkd won out by default.  Go to the <a href="http://kr.github.com/beanstalkd/">beanstalkd</a> website and follow their instructions.  Its <em>that</em> simple.</p>
<h3>How are we gonna keep up with the jobs?</h3>
<p>Although the message queue has a way of peeking into it to learn about number of jobs and what&#8217;s running and the status of said jobs, the background processes I was going to be doing was going to run long enough that I wanted to pass along exactly what stage in the process the job was crunching and this meant building periodic update logging into the actual background job itself.  The problem then is, how do we pass the information cleanly between worker and web app?</a></p>
<p>After some thinking on the matter, I chose to pass along progress updates via the database since all the headaches of I/O contention, persistence and deadlocking had already been solved there.  I wasn&#8217;t quite sure how I was going to format my status updates and post the info to the database until I thought about the great little ProgressBar gem that I was already using for the task when I kicked it off at console.  After a few minutes of looking into the internals of ProgressBar, I knew I could easily extend it to report its status to the database rather than emitting to the console.  An hour later, I had my DbProgressBar and another hour later I had my unit tests written and passing.</p>
<h2>Oh, yeah, the Worker&#8230;</h2>
<p>I digressed from talking about the worker to covering the message queue and passing messages around, so lets get back to that worker script.  As I pointed out earlier, I needed a worker script to do the heavy lifting for the job at hand and I wanted that puppy daemonized.  One thing was perfectly clear in my mind:  I didn&#8217;t want cronjobs nor <b>Threads</b> that depended on the parent processes staying alive (remember how Passenger aggressively scrubs ruby processes from memory!) nor any other means that depended on the parent process within the Ramaze framework kicking off the process directly.</p>
<p>The &#8220;daemons&#8221; rubygem fits the bill perfectly!  I was really surprised by this little gem of a gem. Daemons makes it extremely easy to wrap ordinary Ruby scripts in the usual <em>start|stop|restart|status</em> world you find inside the typcial /etc/init.d/ Linux folder.  What blew my mind was that I didn&#8217;t have to look at the usual long-winded case statement for all those daemonizing commands.  Just focus on writing the main task for the worker, wrap that task in an infinite loop, install it rc.d folders as appropriate and you&#8217;re pretty much done.  The following shows an example worker script:</p>
<pre class="twilight"><span class="Keyword">require</span> <span class="String"><span class="String">'</span>rubygems<span class="String">'</span></span>
<span class="Keyword">require</span> <span class="String"><span class="String">'</span>daemons<span class="String">'</span></span>
<span class="Keyword">require</span> <span class="String"><span class="String">'</span>beanstalk-client<span class="String">'</span></span>
<span class="Keyword">require</span> <span class="String"><span class="String">'</span>sequel<span class="String">'</span></span>

<span class="Variable">ROOT_DIR</span> <span class="Keyword">=</span> <span class="Support">File</span>.<span class="Entity">dirname</span>(<span class="Support">File</span>.<span class="Entity">expand_path</span>(<span class="Variable">__FILE__</span>))
<span class="Variable"><span class="Variable">$</span>LOAD_PATH</span>.<span class="Entity">unshift</span>(<span class="Support">File</span>.<span class="Entity">join</span>(<span class="Variable">ROOT_DIR</span>, <span class="String"><span class="String">'</span>lib<span class="String">'</span></span>))

<span class="Keyword">require</span> <span class="String"><span class="String">'</span>dbprogressbar<span class="String">'</span></span>
<span class="Keyword">require</span> <span class="String"><span class="String">'</span>sequel_output<span class="String">'</span></span>

<span class="Support">Daemons</span>.<span class="Entity">run_proc</span>(<span class="String"><span class="String">'</span>process_astroid_jobs<span class="String">'</span></span>, <span class="Constant"><span class="Constant">:</span>log_output</span> =&gt; <span class="Constant">true</span>) <span class="Keyword">do</span>
  <span class="Variable">DB</span> <span class="Keyword">=</span> <span class="Support">Sequel</span>.<span class="Entity">sqlite</span>(<span class="Support">File</span>.<span class="Entity">join</span>(<span class="Variable">ROOT_DIR</span>, <span class="String"><span class="String">'</span>demo.db<span class="String">'</span></span>))
  <span class="Support">SequelOutput</span>.<span class="Entity">prepare_database</span>(<span class="Variable">DB</span>)
  beanstalk <span class="Keyword">=</span> <span class="Support">Beanstalk</span>::<span class="Entity">Pool</span>.<span class="Entity">new</span>([<span class="String"><span class="String">&quot;</span>0.0.0.0:11300<span class="String">&quot;</span></span>])

  <span class="Keyword">loop</span> <span class="Keyword">do</span>
    job <span class="Keyword">=</span> beanstalk.<span class="Entity">reserve</span>
    jh <span class="Keyword">=</span> job.<span class="Entity">ybody</span>
    puts <span class="String"><span class="String">&quot;</span>processing <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>jh<span class="StringEmbeddedSource">[</span><span class="StringConstant"><span class="StringConstant">:</span>job_id</span><span class="StringEmbeddedSource">]</span><span class="StringEmbeddedSource">}</span></span><span class="String">&quot;</span></span>

    total <span class="Keyword">=</span> <span class="Constant">15</span>
    pbar <span class="Keyword">=</span> <span class="Support">DbProgressBar</span>.<span class="Entity">new</span>(<span class="String"><span class="String">&quot;</span>job #<span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>jh<span class="StringEmbeddedSource">[</span><span class="StringConstant"><span class="StringConstant">:</span>job_id</span><span class="StringEmbeddedSource">]</span><span class="StringEmbeddedSource">}</span></span><span class="String">&quot;</span></span>, total,
      <span class="Support">SequelOutput</span>.<span class="Entity">new</span>(jh[<span class="Constant"><span class="Constant">:</span>job_id</span>], <span class="Variable">DB</span>))

    total.<span class="Entity">times</span> <span class="Keyword">do</span>
      pbar.<span class="Entity">inc</span>
      <span class="Entity">sleep</span>(<span class="Constant">1</span>)
    <span class="Keyword">end</span>

    pbar.<span class="Entity">finish</span>
    puts <span class="String"><span class="String">&quot;</span>finished <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>jh<span class="StringEmbeddedSource">[</span><span class="StringConstant"><span class="StringConstant">:</span>job_id</span><span class="StringEmbeddedSource">]</span><span class="StringEmbeddedSource">}</span></span><span class="String">&quot;</span></span>
    job.<span class="Entity">delete</span>
  <span class="Keyword">end</span>
<span class="Keyword">end</span>
</pre>
<p>There are a few key things to note about the above script.  Firstly, wrapping it in the Daemons.run_proc tells the daemons gem we want to run this like we&#8217;d run a typical server.  SequelOutput is the extension I wrote for ProgressBar to get it to outout to the database and at the start of the script, we ensure the database is ready (namely that the &#8220;progress_bars&#8221; table is created) before we go into our infinite loop to process jobs.</p>
<p>Next up, the loop itself.  Its not a runaway infinite loop that&#8217;ll end up consuming all resources because we are calling the beanstalk queue with &#8220;reserve&#8221; which is a blocking call, thus we sit and wait until a job comes through.  As soon as we get a new job request, we create the DbProgressBar and get to work processing&#8230;.twiddling our thumbs for 15 seconds in this case!  When the job&#8217;s completed, we remove it form the message queue and begin again.</p>
<h2>The Trigger</h2>
<p>Finally, with the back-end done, we could focus on enabling the user to trigger the job on the front-end.  Of course, that was as simple as firing up a connection to the beanstalk server and pushing a job onto the queue in a controller&#8217;s action.  But how do we watch the job and report to the user what&#8217;s going on without overwhelming our server?  The answer came along with a <a href="http://blog.purepistos.net/index.php/2009/01/27/comet-with-ramaze/">&#8220;Comet with Ramaze&#8221; example by Pistos</a>.  What a lovely idea:  Let the server intentionally hold onto the client&#8217;s request until it had something to report back!  I knew it&#8217;d never hold onto the request for more than 2 or 3 seconds, so this was a perfectly workable model for keeping traffic levels sane and timely.</p>
<p>This was also my first time playing around with JSON in AJAX calls and so I got to spend some time flexing my JQuery muscles a bit and also discovered the Ruby json gem that makes it dirt simple to turn a hash into a JSON response.  This is just a small excerpt from the controller/main.rb check_job_progress action:</p>
<pre class="twilight"><span class="Comment"><span class="Comment">#</span> report status as finished when the job is completed</span>
<span class="Keyword">if</span> progress[<span class="Constant"><span class="Constant">:</span>job_finish</span>]
  <span class="Keyword">return</span> {<span class="Constant"><span class="Constant">:</span>progress_text</span> =&gt; <span class="String"><span class="String">&quot;</span>finished.<span class="String">&quot;</span></span>, <span class="Constant"><span class="Constant">:</span>progress_status</span> =&gt; <span class="String"><span class="String">&quot;</span>finished<span class="String">&quot;</span></span>}.<span class="Entity">to_json</span>

<span class="Comment"><span class="Comment">#</span> otherwise report the percent done as the job status </span>
<span class="Keyword">else</span>
  <span class="Keyword">return</span> {<span class="Constant"><span class="Constant">:</span>progress_text</span> =&gt; progress[<span class="Constant"><span class="Constant">:</span>progress_text</span>].<span class="Entity">gsub</span>(<span class="String"><span class="String">'</span> <span class="String">'</span></span>, <span class="String"><span class="String">'</span>&amp;nbsp;<span class="String">'</span></span>),
      <span class="Constant"><span class="Constant">:</span>progress_status</span> =&gt; progress[<span class="Constant"><span class="Constant">:</span>progress_percent</span>]}.<span class="Entity">to_json</span>
<span class="Keyword">end</span>
</pre>
<p>Notice the call to the to_json to convert that hash to JSON response and how clean the Ruby code is even though we&#8217;re passing a rich data object back to our browser client.  I substituted blanks with the &amp;nbsp; character to keep the progress bar from collapsing all those empty blanks between the two vertical bars.  I decided to pass on a progress status so that I could check when things were done and thus stop polling the server for job updates.  This is just a demo, so try not to snicker too much at my use of plain English to convey critical job statuses.  At least the intent is clear!</p>
<p>The JQuery script is also correspondingly simple.</p>
<pre class="twilight"><span class="Storage">function</span> <span class="Entity">check_progress</span>() {
	job_progress_element <span class="Keyword">=</span> <span class="Keyword">$</span>(<span class="String"><span class="String">'</span>#job-progress<span class="String">'</span></span>);
	<span class="Keyword">$</span>.getJSON(<span class="String"><span class="String">'</span>/check_job_progress<span class="String">'</span></span>, {job_id: job_progress_element.attr(<span class="String"><span class="String">'</span>value<span class="String">'</span></span>)},
	  <span class="Storage">function</span>(data){
	    job_progress_element.html(data.progress_text);
      	<span class="Keyword">if</span> (data.progress_status <span class="Keyword">!</span><span class="Keyword">=</span> <span class="String"><span class="String">&quot;</span>finished<span class="String">&quot;</span></span>) check_progress();
	});
}

<span class="Keyword">$</span>(<span class="Support">document</span>).ready(<span class="Storage">function</span>() {
	<span class="Keyword">if</span>(<span class="Keyword">$</span>(<span class="String"><span class="String">'</span>#job-progress<span class="String">'</span></span>).<span class="SupportConstant">length</span>) check_progress();
});
</pre>
<p>As you can see, it simply asks the server for an update and when it receives one, updates itself and asks again!  It will check the job status after each update to see if the job has completed or not, thus stopping its persistent nagging once we&#8217;ve reached the Kingdom of Far, Far Away.</p>
<h3>References</h3>
<p>Here are a few other references, not mentioned above, that were invaluable in helping me pull this solution together.</p>
<p><a href="http://devver.net/blog/2008/10/ruby-beanstalkd-distributed-worker-basics/">Ruby Beanstalkd Distributed Worker Basics</a><br />
<a href="http://snippets.aktagon.com/snippets/212-How-to-create-a-daemon-process-using-Ruby-and-the-daemons-RubyGem">How to Create a Daemon Process Using Ruby and the Daemons RubyGem</a><br />
<a href="http://nubyonrails.com/articles/about-this-blog-beanstalk-messaging-queue">Err the Blog &#8211; About this blog Beanstalk Messaging Queue&#8221;&gt;</a></p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/implementing-ruby-jobs-in-the-background/38/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>What makes a top award candidate, anyhow?</title>
		<link>http://ramblings.gibberishcode.net/archives/what-makes-a-top-award-candidate-anyhow/37</link>
		<comments>http://ramblings.gibberishcode.net/archives/what-makes-a-top-award-candidate-anyhow/37#comments</comments>
		<pubDate>Sat, 01 Aug 2009 16:30:04 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Ruby Language]]></category>
		<category><![CDATA[imagemagick]]></category>
		<category><![CDATA[inkscape]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ramaze]]></category>
		<category><![CDATA[sequel]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=37</guid>
		<description><![CDATA[In our local Linux user group mailing list, one of the participant asked the group for recommendations for open source software projects that should be considered for a prominent publication&#8217;s top 100 awards.  The ensuing discussion got me to wondering:  What is the purpose behind doing the awards?  Most of what I [...]]]></description>
			<content:encoded><![CDATA[<p>In our local Linux user group mailing list, one of the participant asked the group for recommendations for open source software projects that should be considered for a prominent publication&#8217;s top 100 awards.  The ensuing discussion got me to wondering:  What is the purpose behind doing the awards?  Most of what I see talked about are all well-known and well-used, such as git, mercurial, word press, joomla, django, and so on.  Usually, when I look at a list like this, I&#8217;m looking to uncover new and undiscovered projects that have real potential to make a real impact in my daily life and thus was somewhat surprised that such mature projects are being so heavily promoted in the discussions.
</p>
<p>Its not that I don&#8217;t think these tools are worthy contenders.  Most of them, I have used fairly extensively myself over the years.  The suggested contenders are solid and mature projects, but they feel decidedly &#8220;old hat&#8221; to me much as apache, postfix, vim, bind, and the linux kernel probably feels to the system administrator.  In other words, they&#8217;re ubiquitous, so why signal them out with some sort of top 100 reward?
</p>
<p>These days, I have adopted Ruby as my language of choice, so I have moved away from Python and PHP.  While this has largely meant I develop Ruby on Rails applications.  However, as my Ruby skills grow, this also means going far and wide in many other ruby-based tools (such as rake, sake, and rack for system-level or middleware tools).  I am now using ruby for quick and dirty systems administration tasks (such as the short script I wrote to find all currently assigned IP addresses on our office network), automating deployments (capistrano, puppet, chef), marshaling data from one database system to another, and even with extensive image-processing (resizing, conversion of formats, compressing, etc.).
</p>
<p>So what, in my view, warrants a top 100 award recognition?  I like to see new and exciting projects on these lists.  If a project&#8217;s on the list, I like to know that they are extremely active and rapidly gaining mind-share and penetration into the community.  I want to know a little bit about how they put a new spin on an old problem and the impact they have been able to make, not only in the project&#8217;s direct vertical niche, but across the board.  A few years ago, Ruby on Rails arrived on the scene as a game-changer, not only for putting Ruby on the map as a viable language, but as a bona fide development framework for delivering web-based services.  Ruby on Rails turned the Java world on its head and forced Java developers to drastically improve their productivity tools then in common practice; they evangelized convention over configuration and brought many fantastic ideals such as Agile development and RESTful APIs to the forefront of many, many developers&#8217; minds.
</p>
<p>To my way of thinking, though, Ruby on Rails is now old news.  Newcomers will stumble upon Ruby and Rails through word of mouth or simply googling for a solution to some problem they&#8217;re trying to solve.  That&#8217;s the problem I see with top-100 lists paying tribute year after year to the same old mature projects.  Whether its Ruby on Rails or Word Press or Joomla or Django, all of these are easily discovered and well-written about by anybody with decent querying skills.  So what&#8217;s out there today that&#8217;s refreshing and hard to find? Yet, is making a huge impact on the community?  Here are a few that I think are worthy contenders (and yes, they are a little heavy on the Ruby side)&#8230;
</p>
<h2>Rack</h2>
<p><a href="http://rack.rubyforge.org/">Rack: a Ruby Webserver Interface</a>.  What I find phenomenal about Rack is its adoption by so many frameworks that are delivering web-based services.  Micro-frameworks like Ramaze and Camping and Sinatra were early adopters of Rack and such adoption led to far smaller code-bases in each as well as significant performance boosts and, as if that wasn&#8217;t enough, enabled much easier transition from Ruby 1.8 to 1.9.
</p>
<h2>Inkscape and ImageMagick</h2>
<p>Speaking of image processing, I am not sure if many have encountered <a href="http://www.imagemagick.org/script/index.php">ImageMagick</a> and the Ruby bindings offered via <a href="http://rmagick.rubyforge.org/">RMagick</a>, but definitely worth a look-see.  As of this year, I do almost all of my creative graphics work in <a href="http://www.inkscape.org">Inkscape</a> and <a href="http://www.gimp.org/">The Gimp</a> and use ImageMagick to automate some pretty impressive transformations of those images outside the GUI.  Before Inkscape became mature enough to use on daily basis (which, by my reckoning is only in the last 18 months or so), I was heavily reliant on Adobe&#8217;s Illustrator and companion Photoshop apps.  I never would&#8217;ve imagined two years ago that I could completely do away with these packages, let alone begin to automate much of the repetitive tasks that I put those resulting images through (resizing, cropping, web-optimizing, etc.) with a collection of well-written OSS tools.
</p>
<h2>Ramaze and Sequel</h2>
<p>One last pair of tools I think is worthy of consideration, especially for web-based ruby developers is <a href="http://sequel.rubyforge.org/">Sequel</a> and <a href="http://ramaze.net/">Ramaze</a>. Sequel is an object-relational-mapping library that makes working with SQL databases a real pleasure for Ruby developers.  The maintainers seem to have taken the best of the best and rolled those ideas into one coherent and extremely fast library for accessing just about any database out there.  I have fooled around with DataMapper and have worked extensively with ActiveRecord and I must say Sequel really is rung or two above these libraries and I look forward to continuing to adopt Sequel.
</p>
<p>I ran into Sequel by way of the Ramaze project, which is a micro-framework for building web-based applications.  Unlike Ruby on Rails, which tends to generate tons of scaffold/skeletal code for you to begin hacking away on to build your projects, Ramaze takes the opposite tack in that it provides little to no scaffolding or auto-generated code.  Instead, the mindset is squeezing the maximum amount of functionality out of every line of code you do write.  For a Ruby on Rails developer coming to Ramaze, the feeling is very much like the first time I took off on a bicycle without the training wheels attached.  You feel wildly uncontrolled and like you may fall at any moment, but a little encouragement from the warm friendly community gets you going straight and true and the amount of code you&#8217;re NOT writing, reading, reviewing, nor specking tests for really begins to jump out at you!</p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/what-makes-a-top-award-candidate-anyhow/37/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>One ActiveRecord Model Acting as a List and Tree</title>
		<link>http://ramblings.gibberishcode.net/archives/one-activerecord-model-acting-as-a-list-and-tree/33</link>
		<comments>http://ramblings.gibberishcode.net/archives/one-activerecord-model-acting-as-a-list-and-tree/33#comments</comments>
		<pubDate>Thu, 30 Apr 2009 21:44:56 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby Language]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[acts_as_list]]></category>
		<category><![CDATA[acts_as_tree]]></category>
		<category><![CDATA[rails]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=33</guid>
		<description><![CDATA[Occasionally, Rails can appear to make your life extremely easy while silently throwing you a curve-ball.  I needed a model that required a hierarchy while also preserving order of the records.  Although fairly straightforward to set up and start immediately using, there are a couple of &#8220;gotchas&#8221; to watch out for and this [...]]]></description>
			<content:encoded><![CDATA[<p>Occasionally, Rails can appear to make your life extremely easy while silently throwing you a curve-ball.  I needed a model that required a hierarchy while also preserving order of the records.  Although fairly straightforward to set up and start immediately using, there are a couple of &#8220;gotchas&#8221; to watch out for and this article covers those pitfalls and shows how to apply the cool new &#8220;dirty attributes&#8221; feature in ActiveRecord.
</p>
<h2>The Problem</h2>
<p>I am working on a content management system (CMS) where I want the pages to have a hierarchical structure that turns into a menu with sub-menus.  The content manager needs to also be able to order these pages so that the menu structure renders in the desired order.
</p>
<h2>The Solution</h2>
<p>Two plugins jumped to mind almost immediately:  <b>acts_as_tree</b> and <b>acts_as_list</b>.  The tree plugin will manage the hierarchy, hinging off the parent_id field of the model whilist the list plugin uses the position column to manage the order.  What&#8217;s unique here is that I have never used both on one model, but doing so was surprisingly easy:
</p>
<pre class="twilight"><span class="line-numbers">   1 </span> <span class="Keyword">class</span> <span class="Entity">Page<span class="EntityInheritedClass"> <span class="EntityInheritedClass">&lt;</span> ActiveRecord::Base</span></span>
<span class="line-numbers">   2 </span>   acts_as_tree
<span class="line-numbers">   3 </span>   acts_as_list
<span class="line-numbers">   4 </span> <span class="Keyword">end</span>
</pre>
<h2>Constructing a Hierarchical Menu</h2>
<p>Before going too far, if you haven&#8217;t seen the <a href="http://www.alistapart.com/articles/dropdowns">Suckerfish menus</a>, yet, please do check out the article as it will help you quickly see how I approached the menu rendering.  Secondly, to install the two plugins, its a simple pair of command line calls as follows:</p>
<pre class="twilight"><span class="line-numbers">   1 </span> script/plugin install acts_as_tree
<span class="line-numbers">   2 </span> script/plugin install acts_as_list
</pre>
<p>With the CSS handling all the styling, all I needed was to render the nested unordered lists.  I began by grabbing all of the pages at the top level (where parent_id is null) with this bit of code:
</p>
<pre class="twilight"><span class="line-numbers">   1 </span> <span class="Keyword">class</span> <span class="Entity">Page<span class="EntityInheritedClass"> <span class="EntityInheritedClass">&lt;</span> ActiveRecord::Base</span></span>
<span class="line-numbers">   2 </span>   acts_as_tree <span class="Constant"><span class="Constant">:</span>order</span> =&gt; <span class="Constant"><span class="Constant">:</span>position</span>
<span class="line-numbers">   3 </span>   acts_as_list
<span class="line-numbers">   4 </span>
<span class="line-numbers">   5 </span>   <span class="Keyword">def</span> <span class="Entity">self.top_level_pages</span>
<span class="line-numbers">   6 </span>     <span class="Entity">find</span>(<span class="Constant"><span class="Constant">:</span>all</span>, <span class="Constant"><span class="Constant">:</span>conditions</span> =&gt; [<span class="String"><span class="String">&quot;</span>parent_id IS NULL<span class="String">&quot;</span></span>], <span class="Constant"><span class="Constant">:</span>order</span> =&gt; <span class="Constant"><span class="Constant">:</span>position</span>)
<span class="line-numbers">   7 </span>   <span class="Keyword">end</span>
<span class="line-numbers">   8 </span> <span class="Keyword">end</span>
</pre>
<p>If you noticed the &#8220;:order => :position&#8221; clause and thought, &#8220;but acts_as_list handles that for you,&#8221; then you have spotted the first &#8220;gotcha&#8221; I encountered with using both tree and list on a model.  The tree plugin loses the position ordering that the list plugin mixes in and adding these order clauses in preserves the order of the records.  With the query to get the top-level menus in place, I set the @pages variable by calling Page.top_level_pages in the controller and then rendered with this call in my view:
</p>
<pre class="twilight"><span class="line-numbers">   1 </span> <span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">div</span> <span class="MetaTagAll"><span class="MetaTagAll">id</span><span class="MetaTagAll">=</span><span class="String"><span class="String">&quot;</span><span class="String">site-navigation</span><span class="String">&quot;</span></span></span><span class="MetaTagAll">&gt;</span></span>
<span class="line-numbers">   2 </span> 	<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">ul</span><span class="MetaTagAll">&gt;</span></span>
<span class="line-numbers">   3 </span> 		<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> <span class="SupportFunction">render</span><span class="EmbeddedSourceBright">(</span><span class="Constant"><span class="Constant">:</span>partial</span> <span class="EmbeddedSourceBright">=&gt;</span> <span class="String"><span class="String">&quot;</span>/layouts/site_navigation<span class="String">&quot;</span></span><span class="EmbeddedSourceBright">,</span> <span class="Constant"><span class="Constant">:</span>collection</span> <span class="EmbeddedSourceBright">=&gt;</span> <span class="Variable"><span class="Variable">@</span>pages</span><span class="EmbeddedSourceBright">)</span> <span class="EmbeddedSourceBright">%&gt;</span></span>
<span class="line-numbers">   4 </span> 	<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">ul</span><span class="MetaTagAll">&gt;</span></span>
<span class="line-numbers">   5 </span> <span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">div</span><span class="MetaTagAll">&gt;</span></span>
</pre>
<p>To make it all nice and nested, I simply recursively called the same site_navigation partial on the children like so:
</p>
<pre class="twilight"><span class="line-numbers">   1 </span> <span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">li</span><span class="MetaTagInline">&gt;</span></span><span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> <span class="EmbeddedSourceBright"><span class="Entity">link_to</span></span><span class="EmbeddedSourceBright">(</span>site_navigation<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">name</span></span><span class="EmbeddedSourceBright">,</span> <span class="SupportFunction">url_for</span><span class="EmbeddedSourceBright">(</span>site_navigation<span class="EmbeddedSourceBright">)</span><span class="EmbeddedSourceBright">)</span>  <span class="EmbeddedSourceBright">%&gt;</span></span><span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">li</span><span class="MetaTagInline">&gt;</span></span>
<span class="line-numbers">   2 </span> <span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">ul</span><span class="MetaTagAll">&gt;</span></span><span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> <span class="SupportFunction">render</span><span class="EmbeddedSourceBright">(</span><span class="Constant"><span class="Constant">:</span>partial</span> <span class="EmbeddedSourceBright">=&gt;</span> <span class="String"><span class="String">&quot;</span>/layouts/site_navigation<span class="String">&quot;</span></span><span class="EmbeddedSourceBright">,</span> <span class="Constant"><span class="Constant">:</span>collection</span> <span class="EmbeddedSourceBright">=&gt;</span> site_navigation<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">children</span></span><span class="EmbeddedSourceBright">)</span> <span class="EmbeddedSourceBright">%&gt;</span></span><span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">ul</span><span class="MetaTagAll">&gt;</span></span>
</pre>
<p>To give the user ability to move the menu items around, I added &#8220;move_up&#8221; and &#8220;move_down&#8221; actions to the Page Controller in which I called the &#8220;move_higher&#8221; and &#8220;move_lower&#8221; methods that are mixed in by the acts_as_list.  I realized rather quickly that the position index was getting out of sync and added a reindex method to the Page model to clean up the data along with a scope declaration to the model.  Along the way, I also realized that if I moved a page from one parent node to another parent node, I potentially opened a gap in the position index in the collection of Pages and this again breaks the position index sequencing.  The acts_as_list mix-in expects the position index to always go [0, 1, 2, 3, ...N].  Whenever this is not the case, the move_higher and move_lower methods stop working and the user interface no longer responds correctly.  So this is why we care so much about the position index sequence.  So, to handle scoping of the position index sequence correctly and to handle Pages being moved to another parent, we arrive at this final version of the Page model:
</p>
<pre class="twilight"><span class="line-numbers">   1 </span> <span class="Keyword">class</span> <span class="Entity">Page<span class="EntityInheritedClass"> <span class="EntityInheritedClass">&lt;</span> ActiveRecord::Base</span></span>
<span class="line-numbers">   2 </span>   acts_as_tree <span class="Constant"><span class="Constant">:</span>order</span> =&gt; <span class="Constant"><span class="Constant">:</span>position</span>
<span class="line-numbers">   3 </span>   acts_as_list <span class="Constant"><span class="Constant">:</span>scope</span> =&gt; <span class="Constant"><span class="Constant">:</span>parent_id</span>
<span class="line-numbers">   4 </span>
<span class="line-numbers">   5 </span>   before_save <span class="Constant"><span class="Constant">:</span>keep_position_sane</span>
<span class="line-numbers">   6 </span>
<span class="line-numbers">   7 </span>   <span class="Keyword">def</span> <span class="Entity">self.top_level_pages</span>
<span class="line-numbers">   8 </span>     <span class="Entity">find</span>(<span class="Constant"><span class="Constant">:</span>all</span>, <span class="Constant"><span class="Constant">:</span>conditions</span> =&gt; [<span class="String"><span class="String">&quot;</span>parent_id IS NULL<span class="String">&quot;</span></span>], <span class="Constant"><span class="Constant">:</span>order</span> =&gt; <span class="Constant"><span class="Constant">:</span>position</span>)
<span class="line-numbers">   9 </span>   <span class="Keyword">end</span>
<span class="line-numbers">  10 </span>
<span class="line-numbers">  11 </span>   <span class="Keyword">def</span> <span class="Entity">self.reindex_top_level_pages</span>(<span class="Variable">recurse <span class="Keyword">=</span> <span class="Constant">true</span><span class="Variable">,</span> departing_child <span class="Keyword">=</span> <span class="Constant">nil</span></span>)
<span class="line-numbers">  12 </span>     <span class="Entity">reindex_pages</span>(<span class="Variable">self</span>.<span class="Entity">top_level_pages</span>, recurse, departing_child)
<span class="line-numbers">  13 </span>   <span class="Keyword">end</span>
<span class="line-numbers">  14 </span>
<span class="line-numbers">  15 </span>   <span class="Keyword">def</span> <span class="Entity">reindex_children</span>(<span class="Variable">recurse <span class="Keyword">=</span> <span class="Constant">true</span><span class="Variable">,</span> departing_child <span class="Keyword">=</span> <span class="Constant">nil</span></span>)
<span class="line-numbers">  16 </span>     <span class="Support">Page</span>.<span class="Entity">reindex_pages</span>(children, recurse, departing_child)
<span class="line-numbers">  17 </span>   <span class="Keyword">end</span>
<span class="line-numbers">  18 </span>
<span class="line-numbers">  19 </span>   <span class="Keyword">private</span>
<span class="line-numbers">  20 </span>
<span class="line-numbers">  21 </span> <span class="Comment">  <span class="Comment">#</span> takes a given array of pages and recursively (or not) reindexes</span>
<span class="line-numbers">  22 </span> <span class="Comment">  <span class="Comment">#</span> if departing_child is supplied, it is removed from the array so </span>
<span class="line-numbers">  23 </span> <span class="Comment">  <span class="Comment">#</span> that former siblings are reindexed as though it was already </span>
<span class="line-numbers">  24 </span> <span class="Comment">  <span class="Comment">#</span> removed from the collection.</span>
<span class="line-numbers">  25 </span>   <span class="Keyword">def</span> <span class="Entity">self.reindex_pages</span>(<span class="Variable">pages<span class="Variable">,</span> recurse<span class="Variable">,</span> departing_child</span>)
<span class="line-numbers">  26 </span>     pages.<span class="Entity">select</span>{|<span class="Variable">r</span>| r <span class="Keyword">!=</span> departing_child}.<span class="Entity">each_with_index</span> <span class="Keyword">do </span>|<span class="Variable">page</span>, <span class="Variable">index</span>|
<span class="line-numbers">  27 </span>       page.<span class="Entity">reindex_children</span>(<span class="Constant">true</span>) <span class="Keyword">if</span> recurse
<span class="line-numbers">  28 </span>       page.<span class="Entity">update_attributes</span>(<span class="Constant"><span class="Constant">:</span>position</span> =&gt; index <span class="Keyword">+</span> <span class="Constant">1</span>)
<span class="line-numbers">  29 </span>     <span class="Keyword">end</span>
<span class="line-numbers">  30 </span>     <span class="Constant">true</span>
<span class="line-numbers">  31 </span>   <span class="Keyword">end</span>
<span class="line-numbers">  32 </span>
<span class="line-numbers">  33 </span> <span class="Comment">  <span class="Comment">#</span> When the parent id of a node changes, the acts_as_list gets lost, so </span>
<span class="line-numbers">  34 </span> <span class="Comment">  <span class="Comment">#</span> we need to reindex the affected nodes to keep things sane</span>
<span class="line-numbers">  35 </span>   <span class="Keyword">def</span> <span class="Entity">keep_position_sane</span>
<span class="line-numbers">  36 </span>     <span class="Keyword">return</span> <span class="Keyword">unless</span> <span class="Variable">self</span>.<span class="Entity">parent_id_changed?</span>
<span class="line-numbers">  37 </span>
<span class="line-numbers">  38 </span> <span class="Comment">    <span class="Comment">#</span> reindex the group this page is being removed from</span>
<span class="line-numbers">  39 </span>     <span class="Keyword">if</span> <span class="Variable">self</span>.<span class="Entity">parent_id_was</span>.<span class="Entity">nil?</span> <span class="Keyword">then</span>
<span class="line-numbers">  40 </span>       <span class="Support">Page</span>.<span class="Entity">reindex_top_level_pages</span>(<span class="Constant">false</span>, <span class="Variable">self</span>)
<span class="line-numbers">  41 </span>     <span class="Keyword">else</span>
<span class="line-numbers">  42 </span>       <span class="Support">Page</span>.<span class="Entity">find</span>(<span class="Variable">self</span>.<span class="Entity">parent_id_was</span>).<span class="Entity">reindex_children</span>(<span class="Constant">false</span>, <span class="Variable">self</span>)
<span class="line-numbers">  43 </span>     <span class="Keyword">end</span>
<span class="line-numbers">  44 </span>
<span class="line-numbers">  45 </span> <span class="Comment">    <span class="Comment">#</span> make this page the last sibling of the new parent group of pages</span>
<span class="line-numbers">  46 </span>     last_page <span class="Keyword">=</span> (<span class="Variable">self</span>.<span class="Entity">parent_id</span>.<span class="Entity">nil?</span> <span class="Keyword">?</span> <span class="Support">Page</span>.<span class="Entity">top_level_pages</span>.<span class="Entity">last</span> : <span class="Support">Page</span>.<span class="Entity">find</span>(<span class="Variable">self</span>.<span class="Entity">parent_id</span>).<span class="Entity">children</span>.<span class="Entity">last</span>)
<span class="line-numbers">  47 </span>     <span class="Variable">self</span>.<span class="Entity">position</span> <span class="Keyword">=</span> (last_page.<span class="Entity">nil?</span> <span class="Keyword">?</span> <span class="Constant">1</span> : last_page.<span class="Entity">position</span> <span class="Keyword">+</span> <span class="Constant">1</span>)
<span class="line-numbers">  48 </span>     <span class="Constant">true</span>
<span class="line-numbers">  49 </span>   <span class="Keyword">end</span>
<span class="line-numbers">  50 </span> <span class="Keyword">end</span>
</pre>
<p>Check out the &#8220;keep_position_sane&#8221; callback.  You&#8217;ll see a nifty application of the new Dirty records feature of ActiveRecord (which I believe was released with Rails 2.2) and was covered by Ryan Diagle in his post,<br />
<a href="http://ryandaigle.com/articles/2008/3/31/what-s-new-in-edge-rails-dirty-objects">What&#8217;s New in Edge Rails: Dirty Objects</a>.  In order to detect that the parent node was indeed changing and which parent&#8217;s collection the Page belonged to, I checked the &#8220;parent_id_was&#8221; value.  In this case, I had to handle top level pages being moved into another Page&#8217;s collection as well as A sub-page being promoted to top-level.
</p>
<h2>A Handy Rake Task</h2>
<p>If you&#8217;re wondering why the recursive parameter and otherwise unnecessarily complex procedures, its because I also added a rake task to recursively reindex all pages in the menu hierarchy:</p>
<pre class="twilight"><span class="line-numbers">   1 </span>   namespace <span class="Constant"><span class="Constant">:</span>pages</span> <span class="Keyword">do</span>
<span class="line-numbers">   2 </span>     desc <span class="String"><span class="String">&quot;</span>re-index page positions<span class="String">&quot;</span></span>
<span class="line-numbers">   3 </span>     task <span class="Constant"><span class="Constant">:</span>reindex</span> =&gt; <span class="Constant"><span class="Constant">:</span>environment</span> <span class="Keyword">do</span>
<span class="line-numbers">   4 </span>       <span class="Support">Page</span>.<span class="Entity">reindex_top_level_pages</span>
<span class="line-numbers">   5 </span>     <span class="Keyword">end</span>
<span class="line-numbers">   6 </span>   <span class="Keyword">end</span>
</pre>
<h2>Conclusion</h2>
<p>Rails has really come a long ways since its early days, but its still not without its little &#8220;gotchas&#8221; and sometimes its tough to uncover silent failures (like with the position order clause not being rendered from the acts_as_list plugin) when mix-ins from different plug-ins are utilized.  Hopefully, this article shows you a few new tricks and how to utilize somewhat competing plugins safely within one model.  The new Dirty attributes feature of ActiveRecord definitely made the chore of implementing this functionality much easier and sane than it would&#8217;ve been back in the Rails 1.x days.</p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/one-activerecord-model-acting-as-a-list-and-tree/33/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails vs. Ramaze Performance Comparison</title>
		<link>http://ramblings.gibberishcode.net/archives/rails-vs-ramaze-performance-comparison/31</link>
		<comments>http://ramblings.gibberishcode.net/archives/rails-vs-ramaze-performance-comparison/31#comments</comments>
		<pubDate>Thu, 19 Feb 2009 21:07:24 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Servers]]></category>
		<category><![CDATA[Systems]]></category>
		<category><![CDATA[mri ruby]]></category>
		<category><![CDATA[passenger]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ramaze]]></category>
		<category><![CDATA[ree ruby]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=31</guid>
		<description><![CDATA[One of my biggest concerns of late is that my &#8220;more than just a little trivial&#8221; Rails projects seem to find their way straight into the heavyweight category in no time at all.  While I am quite hopeful that Merb being the 3.0 version of Rails will resolve many of the issues I face [...]]]></description>
			<content:encoded><![CDATA[<p>One of my biggest concerns of late is that my &#8220;more than just a little trivial&#8221; Rails projects seem to find their way straight into the heavyweight category in no time at all.  While I am quite hopeful that Merb being the 3.0 version of Rails will resolve many of the issues I face today, I have no idea when I can truly count on Rails 3.0&#8217;s arrival at the party.  Thus, I have begun looking at other frameworks that are available today.</p>
<h2>Introducing Ramaze</h2>
<p>One I found is <a href="http://www.ramaze.net">Ramaze</a>.  I have to say that Ramaze is a very minimalist approach to a framework that is actually rather enlightening.  For one coming from a Rails&#8217; world, it can feel a bit sparse at first.  But lately, I&#8217;m attributing my lack of comfort to being put on my toes to do some actual real Ruby coding.  Its both a little scary and liberating at the same time.  I have found that I am enjoying Ruby a lot more as a result of my exposure to Ramaze and my thought process is actually radically changing, almost like a Visual Basic programmer going to Borland Delphi might feel.</p>
<p>So I decided to take a hard look at performance metrics between Rails and Ramaze&#8217;s.  At the same time, I wanted to see how MRI 1.8.7 stacked up against Ruby Enterprise Ed. 1.8.6, so I&#8217;m satisfying a dual curiosity herein.  Being quite happy with <a href="http://www.mod_rails.com">Phusion Passenger</a>, I decided to set things up with Apache 2.2.9 + Passenger + Rails/Ramaze.  Since I&#8217;m quite comfortable with ERB and ActiveRecord, I tweaked Ramaze to be a bit more like the familiar Rails world I am familiar with.</p>
<h2>Un-DRYing the Results</h2>
<p>There&#8217;s no point in generating a lot of data and reporting on it if others cannot repeat yourself (CRY!) in replicating the results, so with that in mind, I attempt to refrain from further bad turn of words by busying myself in pushing everything I utilized to <a href="http://github.com/mwlang/benchmarks/tree/master">github.com</a> and documenting the basic <a href="http://ramblings.gibberishcode.net/archives/bootstrap-ubuntu-server-810-intrepid-64-bit/29">bootstrapping of Ubuntu Intrepid</a>.  For these tests in particular, I used two scripts, <a href="http://github.com/mwlang/bootstrap-scripts/blob/af44b371a24a79820c98fcf9cfe014b7a523a24a/ubuntu/intrepid/bootstrap-passenger-std.sh">bootstrap-passenger-std.sh</a> and <a href="http://github.com/mwlang/bootstrap-scripts/blob/af44b371a24a79820c98fcf9cfe014b7a523a24a/ubuntu/intrepid/bootstrap-passenger-ent.sh">bootstrap-passenter-ent.sh</a> to set up four distinct configurations under the Ruby1.8 interpreter.  Ruby 1.9.1. was a bit difficult to set up and there is a <a href="http://github.com/mwlang/bootstrap-scripts/blob/af44b371a24a79820c98fcf9cfe014b7a523a24a/ubuntu/intrepid/bootstrap-passenger-191.sh">bootstrap-passenger-191.sh</a> script that I assembled as I installed things, but I haven&#8217;t run it to ensure it works end-to-end.   </p>
<table style="width: 70%;" border="1">
<thead>
<tr>
<td style="text-align: center;" colspan="5">Apache 2.2.2</td>
</tr>
<tr>
<td style="text-align: center;" colspan="4">Passenger 2.0.6<br/>(gem)</td>
<td style="text-align: center;">Passenger 2.1.0<br/>(source)</td>
</tr>
<tr>
<td style="text-align: center;" colspan="2">Rails 2.2.2</td>
<td style="text-align: center;" colspan="2">Ramaze 2009.01</td>
<td style="text-align: center;" colspan="1">Ramaze 2009.01</td>
</tr>
<tr>
<td style="text-align: center;">MRI Ruby 1.8.7<br/>package</td>
<td style="text-align: center;">Ent. Ruby 1.8.6<br/>source</td>
<td style="text-align: center;">MRI Ruby 1.8.7<br/>package</td>
<td style="text-align: center;">Ent. Ruby 1.8.6<br/>source</td>
<td style="text-align: center;">MRI Ruby 1.9.1<br/>source</td>
</tr>
</thead>
</table>
<p>I utilized this simple call to Apache Bench to run through the four test scenarios:<br />
All data collected was based on 10,000 requests at 100 concurrent users after an initial &#8220;warmup&#8221; of the passenger threads with start of 100 requests at 10 concurrent users.  The following command shows the basic set of parameters issued to Apache Bench:</p>
<pre class="twilight">
ab -n 10000 -c 100 http://demo.u64rails01.local/posts
</pre>
<p><br/></p>
<h2>What was tested?</h2>
<p>In order to compare, as close as possible, apples to apples, I opted to use Active Record and ERubis in Ramaze to set up the same MVC classes in both the Rails and Ramaze project.  ActiveRecord is probably the heaviest weighted ORM that can be utilized with Ramaze.  I tried briefly to get Erubis working with Rails so that the two frameworks&#8217; projects would be more closely aligned than the out-of-box ERB rendering Rails ships with would have afforded.  I did attempt Erubis with Rails, however, I was either doing something very wrong or Erubis under Rails takes a sizable performance hit and I stuck with out-of-box ERB for these tests given its better performance.  As such, Rails uses out of box ERB rendering in these tests.</p>
<p>The <a href="http://github.com/mwlang/benchmarks/tree/0baffeb9cf3eb514912c6de34b64dc2ce25c2e31/2009/02">application itself</a> is ridiculously simple, offering only one model and performing only a read against the database, but hopefully, an effective start towards building this benchmark framework towards more substantive benchmark tests to come.  For now, lets take a look at how Rails and Ramaze stack up to each other and what affect the underlying interpreter can have on performance.  Standard packaged Main Ruby Interpreter (MRI) 1.8.7 consisted of simple package install provided by the Ubuntu Intrepid repositories whle <a href="http://www.rubyenterpriseedition.com/">Ruby Enterprise Edition</a> (REE) 1.8.6, which hails from the same folks bringing you Phusion Passenger, is compiled from source.</p>
<p>As a bonus, I also compiled and clocked metrics for Ramaze on 1.9.1.  This was a tricky environment to get set up and working.  And my initial results made me think I did something horribly wrong with compiling and configuring Ruby 1.9.1.  However, I fully replicated Antonio Cangiano&#8217;s benchmarks in my test environment (see <a href="http://antoniocangiano.com/2008/12/09/the-great-ruby-shootout-december-2008/">The Great Ruby Shootout (December 2008)</a>) and MRI 1.9.1. did indeed crush the other Ruby interpreters in Fibonacci number crunching (amongst others).  The theory tossed around in the Ramaze IRC channel was that 1.9.1. change in implementation of the String class (and it being unicode native now) slows things down a good bit with string processing.</p>
<h2>The Results</h2>
<p>The following table tabulates the results gathered from Apache Bench as well as passenger-memory-stat.  I ran a short run to warm things up (100 requests, 10 concurrently).  And then ran the big bench at 10,000 requests, 100 concurrently, and then ran again and recorded the results.  At around 5,000 requests, I ran passenger-memory-stat to collect the data during mid-processing and then again at the end.  These tests were run on a Ubuntu 64-bit Intrepid 8.10 virtual server that was allocated 1 CPU core and 512MB of RAM.  Swap space was never triggered (0k utilization), and CPU utilization was roughly 85% within the Virtual Machine during the test runs.  The host machine, which is four core CPU, showed one core busy at near 100% with the other three cores pretty much idle.</p>
<table border="0" cellspacing="0" frame="void" rules="none">
<tbody>
<tr>
<td width="138" height="17" align="left"><strong></strong></td>
<td width="86" align="right"><strong>mri_rails</strong></td>
<td width="86" align="right"><strong>ree_rails</strong></td>
<td width="86" align="right"><strong>mri_ramaze</strong></td>
<td width="86" align="right"><strong>ree_ramaze</strong></td>
<td width="86" align="right"><strong>191_ramaze</strong></td>
<td width="86" align="left"><strong>units</strong></td>
</tr>
<tr>
<td height="16" align="right"><strong>Time taken for tests</strong></td>
<td align="right">489.24</td>
<td align="right">379.76</td>
<td align="right">397.43</td>
<td align="right">287.5</td>
<td align="right">351.95</td>
<td align="left"><em>seconds</em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Complete requests</strong></td>
<td align="right">10000</td>
<td align="right">10000</td>
<td align="right">10000</td>
<td align="right">10000</td>
<td align="right">10000</td>
<td align="left"><em></em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Failed requests</strong></td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="left"><em></em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Write errors</strong></td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="left"><em></em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Total transferred</strong></td>
<td align="right">36670146</td>
<td align="right">36668229</td>
<td align="right">18130000</td>
<td align="right">18130000</td>
<td align="right">18460000</td>
<td align="left"><em>bytes</em></td>
</tr>
<tr>
<td height="16" align="right"><strong>HTML transferred</strong></td>
<td align="right">30500000</td>
<td align="right">30500000</td>
<td align="right">14480000</td>
<td align="right">14480000</td>
<td align="right">14680000</td>
<td align="left"><em>bytes</em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Requests per second</strong></td>
<td align="right">20.44</td>
<td align="right">26.33</td>
<td align="right">25.19</td>
<td align="right">34.78</td>
<td align="right">28.41</td>
<td align="left"><em>[#/sec] (mean)</em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Time per request</strong></td>
<td align="right">4892.42</td>
<td align="right">3797.56</td>
<td align="right">3970.43</td>
<td align="right">2875.03</td>
<td align="right">3519.49</td>
<td align="left"><em>[ms] (mean)</em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Time per request</strong></td>
<td align="right">48.92</td>
<td align="right">37.98</td>
<td align="right">39.7</td>
<td align="right">28.75</td>
<td align="right">35.2</td>
<td align="left"><em>[ms] (mean, across all concurrent requests)</em></td>
</tr>
<tr>
<td height="17" align="right"><strong>Transfer rate</strong></td>
<td align="right">73.19</td>
<td align="right">94.29</td>
<td align="right">44.59</td>
<td align="right">61.58</td>
<td align="right">51.22</td>
<td align="left"><em>[Kbytes/sec] received</em></td>
</tr>
<tr>
<td height="16" align="right"><strong>Total private dirty RSS</strong></td>
<td align="right">323.73</td>
<td align="right">180.89</td>
<td align="right">221.11</td>
<td align="right">221.51</td>
<td align="right">210.73</td>
<td align="left"><em>MB</em></td>
</tr>
</tbody>
</table>
<h2>Throughput</h2>
<p>Everybody likes to <a href="http://www.therailsway.com/2009/1/6/requests-per-second">talk about throughput</a>, so lets start there.  As you can see, MRI and Rails was the worst performer while REE and Ramaze clocked in with the highest throughput in terms of requests per second.  Be forewarned that throughput doesn&#8217;t necessarily equate to user response times.  This metric simply tells you the load at which your system is capable of delivering content at.</p>
<p><img src='http://github.com/mwlang/benchmarks/raw/0baffeb9cf3eb514912c6de34b64dc2ce25c2e31/2009/02/throughput.png' alt='throughput' class='alignnone' /></p>
<h2>Time per Request</h2>
<p>Time per request helps you see about how long an average user request takes for a given load.  As you can see here, with times in the milliseconds, we&#8217;re talking about numbers that will easily be swallowed in the noise of network latency.  Even so, its not hard to be impressed by what the REE folks managed to pull out of their hat with regards to performance on the main ruby interpreter.</p>
<p><img src='http://github.com/mwlang/benchmarks/raw/0baffeb9cf3eb514912c6de34b64dc2ce25c2e31/2009/02/time_per_request.png' alt='Time per Request' class='alignnone' /></p>
<h2>Memory Consumption</h2>
<p>This final graph shows the sizeable dent REE makes in memory consumption for running a Rails application.  Ramaze is already pretty efficient and lean and REE made practically no dent in memory consumption here.  However, REE&#8217;s use of the faster memory allocation routines does have a good effect on boosting Ramaze&#8217;s performance (as seen in above graphs), so there&#8217;s still lots to be gained by running Ramaze with REE.</p>
<p><img src='http://github.com/mwlang/benchmarks/raw/0baffeb9cf3eb514912c6de34b64dc2ce25c2e31/2009/02/memory_usage.png' alt='Memory Usage' class='alignnone' /></p>
<h2>Conclusion</h2>
<p>For me, I have two very, very viable solutions before me.  Rails on Enterprise Ruby or Ramaze on Ruby 1.8.7.  The final choice comes down to how much I can bet on my own Ruby prowess.   Ramaze is a very lean framework that gets you going, but doesn&#8217;t get you a nine inch pillowed mattress topping for your bed like Rails does.  Because Ramaze is so lean, I realize I will have to really take my Ruby skills to the next level and truly understand the ruby code that other developers produce.  Unlike Rails, where there&#8217;s gobs and gobs of plugins and blogs on the topic that make pretty much any need simple to satisfy and get working, I have to know my Ruby to get a solution implemented on Ramaze.  Not a bad thing, but certainly a more challenging and potentially rewarding path to take.</p>
<p>Aside from my personal concerns about making the jump, looking at these results, it is good to see that I have options and how easy it is to get a good deployment up and working compared to 3 or 4 years ago when I was banging my head against the wall for days on end to keep lighttpd + fcgi processes up and running around the clock.  In these tests, it was very, very satisfying that not one single crash or dropped request was recorded in all the benchmarking I performed.  Mongrel came along and made a big impact, but you still needed something like monit to watch Mongrel and restart it on ocvasion.  Now Passenger has come along and made yet another big impact in the ease of deploying Rails, Ramaze, or any of the other ruby-based frameworks.  We&#8217;ve come a long ways, indeed.  I, for one, certainly look forward to what the Ruby sphere will bring us over the next couple of years.</p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/rails-vs-ramaze-performance-comparison/31/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Ultraviolet gives new life to Syntax highlighting</title>
		<link>http://ramblings.gibberishcode.net/archives/ultraviolet-gives-new-life-to-syntax-highlighting/27</link>
		<comments>http://ramblings.gibberishcode.net/archives/ultraviolet-gives-new-life-to-syntax-highlighting/27#comments</comments>
		<pubDate>Thu, 05 Feb 2009 08:30:44 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[mama]]></category>
		<category><![CDATA[oniguruma]]></category>
		<category><![CDATA[textmate]]></category>
		<category><![CDATA[textpow]]></category>
		<category><![CDATA[ultraviolet]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=27</guid>
		<description><![CDATA[I am tired of Google&#8217;s Syntax highlighter.  If I accidentally switch to Visual mode in the editor and do some edits and switch back to HTML mode, then I lose the class=&#8221;code&#8221; moniker and I have to go through the entire post and fix.
Another drawback I have with Google Syntax highlighter is that the page [...]]]></description>
			<content:encoded><![CDATA[<p>I am tired of Google&#8217;s Syntax highlighter.  If I accidentally switch to Visual mode in the editor and do some edits and switch back to HTML mode, then I lose the class=&#8221;code&#8221; moniker and I have to go through the entire post and fix.</p>
<p>Another drawback I have with Google Syntax highlighter is that the page renders without highlighting and then all the code listings change to syntax highlighted text a few moments later.</p>
<p>Introducing <a href="http://ultraviolet.rubyforge.org/index.xhtml" target="_blank">Ultraviolet</a>, a syntax highlighter supporting over 50 syntaxes and any <a href="http://macromates.com/" target="_blank">TextMate</a> theme.  Ultraviolet is based on <a href="http://www.geocities.jp/kosako3/oniguruma/" target="_blank">Oniguruma</a>, a regular expression library that comes standard with Ruby 1.9.  Ultraviolet requires a little more effort for me to cut and paste, but I am definitely much happier with the end results and Wordpress no longer mungs my posts.  Only real complaint I have is that I can&#8217;t read the posted code inline in HTML format (but I can read it in Visual mode!).</p>
<h2>Ruby Script</h2>
<pre class="twilight"><span class="line-numbers">   1 </span> <span class="Keyword">require</span> <span class="String"><span class="String">'</span>rubygems<span class="String">'</span></span>
<span class="line-numbers">   2 </span> <span class="Keyword">require</span> <span class="String"><span class="String">'</span>ramaze<span class="String">'</span></span>
<span class="line-numbers">   3 </span> <span class="Keyword">require</span> <span class="String"><span class="String">'</span>maruku<span class="String">'</span></span>
<span class="line-numbers">   4 </span> <span class="Keyword">require</span> <span class="String"><span class="String">'</span>sequel<span class="String">'</span></span>
<span class="line-numbers">   5 </span>
<span class="line-numbers">   6 </span> <span class="Variable"><span class="Variable">$</span>LOAD_PATH</span>.<span class="Entity">unshift</span>(__DIR__)
<span class="line-numbers">   7 </span>
<span class="line-numbers">   8 </span> <span class="Keyword">require</span> <span class="String"><span class="String">'</span>env<span class="String">'</span></span>
<span class="line-numbers">   9 </span>
<span class="line-numbers">  10 </span> <span class="Keyword">require</span> <span class="String"><span class="String">'</span>vendor/flickr<span class="String">'</span></span>
<span class="line-numbers">  11 </span> <span class="Keyword">require</span> <span class="String"><span class="String">'</span>vendor/haml_maruku_filter<span class="String">'</span></span>
<span class="line-numbers">  12 </span> <span class="Keyword">require</span> <span class="String"><span class="String">'</span>vendor/image_science_cropped_resize<span class="String">'</span></span>
<span class="line-numbers">  13 </span>
<span class="line-numbers">  14 </span> <span class="Keyword">require</span> <span class="String"><span class="String">'</span>model/init<span class="String">'</span></span>
<span class="line-numbers">  15 </span> <span class="Keyword">require</span> <span class="String"><span class="String">'</span>controller/init<span class="String">'</span></span>
<span class="line-numbers">  16 </span>
<span class="line-numbers">  17 </span> <span class="Keyword">require</span> <span class="String"><span class="String">'</span>db/init<span class="String">'</span></span> <span class="Keyword">if</span> <span class="Variable">SOCIAR</span>.<span class="Entity">mode</span> <span class="Keyword">==</span> <span class="Constant"><span class="Constant">:</span>dev</span>
<span class="line-numbers">  18 </span>
<span class="line-numbers">  19 </span> r <span class="Keyword">=</span> <span class="Variable">SOCIAR</span>.<span class="Entity">ramaze</span>
<span class="line-numbers">  20 </span>
<span class="line-numbers">  21 </span> <span class="Comment"><span class="Comment">=begin</span></span>
<span class="line-numbers">  22 </span> <span class="Comment">if r.gzip</span>
<span class="line-numbers">  23 </span> <span class="Comment">  require 'ramaze/contrib/gzip_filter'</span>
<span class="line-numbers">  24 </span> <span class="Comment">  gzip = Ramaze::Filter::Gzip</span>
<span class="line-numbers">  25 </span> <span class="Comment">  gzip.trait :threshold =&gt; 1</span>
<span class="line-numbers">  26 </span> <span class="Comment">  Ramaze::Dispatcher::Action::FILTER &lt;&lt; gzip</span>
<span class="line-numbers">  27 </span> <span class="Comment"><span class="Comment">=end</span></span>
<span class="line-numbers">  28 </span>
<span class="line-numbers">  29 </span> <span class="Support">Ramaze</span>.<span class="Entity">start</span> <span class="Constant"><span class="Constant">:</span>adapter</span> =&gt; r.<span class="Entity">adapter</span>,
<span class="line-numbers">  30 </span>              <span class="Constant"><span class="Constant">:</span>host</span> =&gt; r.<span class="Entity">host</span>,
<span class="line-numbers">  31 </span>              <span class="Constant"><span class="Constant">:</span>port</span> =&gt; r.<span class="Entity">port</span>,
<span class="line-numbers">  32 </span>              <span class="Constant"><span class="Constant">:</span>boring</span> =&gt; r.<span class="Entity">boring</span></pre>
<h2>Shell Script</h2>
<pre class="twilight"><span class="line-numbers">   1 </span> <span class="Comment"><span class="Comment">#</span>!/bin/sh</span>
<span class="line-numbers">   2 </span>
<span class="line-numbers">   3 </span> <span class="Comment"><span class="Comment">#</span>## BEGIN INIT INFO</span>
<span class="line-numbers">   4 </span> <span class="Comment"><span class="Comment">#</span> Provides:          lm-sensors</span>
<span class="line-numbers">   5 </span> <span class="Comment"><span class="Comment">#</span> Required-Start:    $local_fs</span>
<span class="line-numbers">   6 </span> <span class="Comment"><span class="Comment">#</span> Required-Stop:</span>
<span class="line-numbers">   7 </span> <span class="Comment"><span class="Comment">#</span> Default-Start:     S</span>
<span class="line-numbers">   8 </span> <span class="Comment"><span class="Comment">#</span> Default-Stop:</span>
<span class="line-numbers">   9 </span> <span class="Comment"><span class="Comment">#</span> Short-Description: lm-sensors</span>
<span class="line-numbers">  10 </span> <span class="Comment"><span class="Comment">#</span> Description:       hardware health monitoring</span>
<span class="line-numbers">  11 </span> <span class="Comment"><span class="Comment">#</span>## END INIT INFO</span>
<span class="line-numbers">  12 </span>
<span class="line-numbers">  13 </span> . /lib/lsb/init-functions
<span class="line-numbers">  14 </span>
<span class="line-numbers">  15 </span> [ -f /etc/default/rcS ] <span class="Keyword">&amp;&amp;</span> . /etc/default/rcS
<span class="line-numbers">  16 </span> PATH=/bin:/usr/bin:/sbin:/usr/sbin
<span class="line-numbers">  17 </span> PROGRAM=/usr/bin/sensors
<span class="line-numbers">  18 </span>
<span class="line-numbers">  19 </span> test -x <span class="Variable"><span class="Variable">$</span>PROGRAM</span> <span class="Keyword">||</span> exit 0
<span class="line-numbers">  20 </span>
<span class="line-numbers">  21 </span> <span class="Keyword">case</span> <span class="String"><span class="String">&quot;</span><span class="Variable"><span class="Variable">$</span>1</span><span class="String">&quot;</span></span> <span class="Keyword">in</span>
<span class="line-numbers">  22 </span>   start)
<span class="line-numbers">  23 </span> 	log_begin_msg <span class="String"><span class="String">&quot;</span>Setting sensors limits<span class="String">&quot;</span></span>
<span class="line-numbers">  24 </span> 	<span class="Keyword">if</span> [ <span class="String"><span class="String">&quot;</span><span class="Variable"><span class="Variable">$</span>VERBOSE</span><span class="String">&quot;</span></span> = <span class="String"><span class="String">&quot;</span>no<span class="String">&quot;</span></span> ]<span class="Keyword">;</span> <span class="Keyword">then</span>
<span class="line-numbers">  25 </span> 		/usr/bin/sensors -s <span class="Keyword">1&gt;</span> /dev/null <span class="Keyword">2&gt;</span> /dev/null
<span class="line-numbers">  26 </span> 		/usr/bin/sensors <span class="Keyword">1&gt;</span> /dev/null <span class="Keyword">2&gt;</span> /dev/null
<span class="line-numbers">  27 </span> 	<span class="Keyword">else</span>
<span class="line-numbers">  28 </span> 		/usr/bin/sensors -s
<span class="line-numbers">  29 </span> 		/usr/bin/sensors <span class="Keyword">&gt;</span> /dev/null
<span class="line-numbers">  30 </span> 	<span class="Keyword">fi</span>
<span class="line-numbers">  31 </span> 	log_end_msg <span class="Variable"><span class="Variable">$</span>?</span>
<span class="line-numbers">  32 </span> 	<span class="Keyword">;</span><span class="Keyword">;</span>
<span class="line-numbers">  33 </span>   stop)
<span class="line-numbers">  34 </span> 	<span class="Keyword">;</span><span class="Keyword">;</span>
<span class="line-numbers">  35 </span>   force-reload<span class="Keyword">|</span>restart)
<span class="line-numbers">  36 </span> 	<span class="Variable"><span class="Variable">$</span>0</span> start
<span class="line-numbers">  37 </span> 	<span class="Keyword">;</span><span class="Keyword">;</span>
<span class="line-numbers">  38 </span>   *)
<span class="line-numbers">  39 </span> 	log_success_msg <span class="String"><span class="String">&quot;</span>Usage: /etc/init.d/sensors {start|stop|restart|force-reload}<span class="String">&quot;</span></span>
<span class="line-numbers">  40 </span> 	exit 1
<span class="line-numbers">  41 </span> <span class="Keyword">esac</span>
<span class="line-numbers">  42 </span>
<span class="line-numbers">  43 </span> exit 0
</pre>
<h2>Apache Config</h2>
<pre class="twilight"><span class="line-numbers">   1 </span> <span class="MarkupTag"><span class="MarkupTag">&lt;</span><span class="MarkupNameOfTag">VirtualHost</span> <span class="MarkupTag">*:80</span><span class="MarkupTag">&gt;</span></span>
<span class="line-numbers">   2 </span> 	<span class="LibraryConstant">ServerName</span> www.stinger.local
<span class="line-numbers">   3 </span> 	<span class="LibraryConstant">ServerAdmin</span> webmaster@localhost
<span class="line-numbers">   4 </span>
<span class="line-numbers">   5 </span> 	<span class="LibraryConstant">DocumentRoot</span> /var/www/
<span class="line-numbers">   6 </span> 	<span class="MarkupTag"><span class="MarkupTag">&lt;</span><span class="MarkupNameOfTag">Directory</span> <span class="MarkupTag">/&gt;</span></span>
<span class="line-numbers">   7 </span> 		<span class="LibraryConstant">Options</span> FollowSymLinks
<span class="line-numbers">   8 </span> 		<span class="LibraryConstant">AllowOverride</span> None
<span class="line-numbers">   9 </span> 	<span class="MarkupTag"><span class="MarkupTag">&lt;/</span><span class="MarkupNameOfTag">Directory</span><span class="MarkupTag">&gt;</span></span>
<span class="line-numbers">  10 </span> 	<span class="MarkupTag"><span class="MarkupTag">&lt;</span><span class="MarkupNameOfTag">Directory</span> /var/www<span class="MarkupTag">/&gt;</span></span>
<span class="line-numbers">  11 </span> 		<span class="LibraryConstant">Options</span> Indexes FollowSymLinks MultiViews
<span class="line-numbers">  12 </span> 		<span class="LibraryConstant">AllowOverride</span> None
<span class="line-numbers">  13 </span> 		<span class="LibraryConstant">Order</span> allow,deny
<span class="line-numbers">  14 </span> 		allow from all
<span class="line-numbers">  15 </span> 	<span class="MarkupTag"><span class="MarkupTag">&lt;/</span><span class="MarkupNameOfTag">Directory</span><span class="MarkupTag">&gt;</span></span>
<span class="line-numbers">  16 </span>
<span class="line-numbers">  17 </span> 	<span class="LibraryConstant">ScriptAlias</span> /cgi-bin/ /usr/lib/cgi-bin/
<span class="line-numbers">  18 </span> 	<span class="MarkupTag"><span class="MarkupTag">&lt;</span><span class="MarkupNameOfTag">Directory</span> &quot;/usr/lib/cgi-bin&quot;<span class="MarkupTag">&gt;</span></span>
<span class="line-numbers">  19 </span> 		<span class="LibraryConstant">AllowOverride</span> None
<span class="line-numbers">  20 </span> 		<span class="LibraryConstant">Options</span> +ExecCGI -MultiViews +SymLinksIfOwnerMatch
<span class="line-numbers">  21 </span> 		<span class="LibraryConstant">Order</span> allow,deny
<span class="line-numbers">  22 </span> 		<span class="LibraryConstant">Allow</span> from all
<span class="line-numbers">  23 </span> 	<span class="MarkupTag"><span class="MarkupTag">&lt;/</span><span class="MarkupNameOfTag">Directory</span><span class="MarkupTag">&gt;</span></span>
<span class="line-numbers">  24 </span>
<span class="line-numbers">  25 </span> 	<span class="LibraryConstant">ErrorLog</span> /var/log/apache2/error.log
<span class="line-numbers">  26 </span>
<span class="line-numbers">  27 </span> 	<span class="Comment"><span class="Comment">#</span> Possible values include: debug, info, notice, warn, error, crit,</span>
<span class="line-numbers">  28 </span> 	<span class="Comment"><span class="Comment">#</span> alert, emerg.</span>
<span class="line-numbers">  29 </span> 	<span class="LibraryConstant">LogLevel</span> warn
<span class="line-numbers">  30 </span>
<span class="line-numbers">  31 </span> 	<span class="LibraryConstant">CustomLog</span> /var/log/apache2/access.log combined
<span class="line-numbers">  32 </span>
<span class="line-numbers">  33 </span>     <span class="LibraryConstant">Alias</span> /doc/ <span class="String"><span class="String">&quot;</span>/usr/share/doc/<span class="String">&quot;</span></span>
<span class="line-numbers">  34 </span>     <span class="MarkupTag"><span class="MarkupTag">&lt;</span><span class="MarkupNameOfTag">Directory</span> <span class="MarkupTag">&quot;/usr/share/doc/&quot;</span><span class="MarkupTag">&gt;</span></span>
<span class="line-numbers">  35 </span>         <span class="LibraryConstant">Options</span> Indexes MultiViews FollowSymLinks
<span class="line-numbers">  36 </span>         <span class="LibraryConstant">AllowOverride</span> None
<span class="line-numbers">  37 </span>         <span class="LibraryConstant">Order</span> deny,allow
<span class="line-numbers">  38 </span>         <span class="LibraryConstant">Deny</span> from all
<span class="line-numbers">  39 </span>         <span class="LibraryConstant">Allow</span> from 127.0.0.0/255.0.0.0 ::1/128
<span class="line-numbers">  40 </span>     <span class="MarkupTag"><span class="MarkupTag">&lt;/</span><span class="MarkupNameOfTag">Directory</span><span class="MarkupTag">&gt;</span></span>
<span class="line-numbers">  41 </span>
<span class="line-numbers">  42 </span> <span class="MarkupTag"><span class="MarkupTag">&lt;/</span><span class="MarkupNameOfTag">VirtualHost</span><span class="MarkupTag">&gt;</span></span>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/ultraviolet-gives-new-life-to-syntax-highlighting/27/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ramaze and ActiveRecord</title>
		<link>http://ramblings.gibberishcode.net/archives/ramaze-and-activerecord/26</link>
		<comments>http://ramblings.gibberishcode.net/archives/ramaze-and-activerecord/26#comments</comments>
		<pubDate>Wed, 04 Feb 2009 07:49:01 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby Language]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[benchmarks]]></category>
		<category><![CDATA[erubis]]></category>
		<category><![CDATA[monkey patch]]></category>
		<category><![CDATA[ramaze]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=26</guid>
		<description><![CDATA[Thanks to the great folks on IRC over at Freenode#ramaze, I was able to not only get Ramaze working with Erubis and Activerecord for a pseudo apples to apples comparison of Rails vs. Ramaze performance benching, but I was also able to get Apache 2.2.9 talking to Passenger to Ramaze.  This quick post will [...]]]></description>
			<content:encoded><![CDATA[<p>Thanks to the great folks on IRC over at Freenode#ramaze, I was able to not only get Ramaze working with Erubis and Activerecord for a pseudo apples to apples comparison of Rails vs. Ramaze performance benching, but I was also able to get Apache 2.2.9 talking to Passenger to Ramaze.  This quick post will take you through the basics.</p>
<h2>Environment</h2>
<p>This post will guide you through setting up the following environment on Ubuntu Intrepid (8.10):</p>
<ul>
<li><a href="http://httpd.apache.org/docs/2.2/">Apache 2.2.9</a></li>
<li><a href="http://www.modrails.com/">Passenger 2.0.6</a></li>
<li><a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html">ActiveRecord 2.2.2</a></li>
<li><a href="http://ramaze.net/">Ramaze 2009.01</a></li>
<li><a href="http://www.kuwata-lab.com/erubis/">Erubis 2.6.2</a></li>
<li><a href="http://www.mysql.com/">MySql 5.0.67 (assumed installed)</a></li>
</ul>
<p>To get started:</p>
<pre  name="code" class="ruby:nocontrols">
sudo apt-get install apache2 passenger
sudo passenger-install-apache2-module
</pre>
<p>Install the Rack, Ramaze, Activerecord, and Erubis gems</p>
<pre  name="code" class="ruby:nocontrols">
sudo gem install rack, ramaze, activerecord, erubis
</pre>
<h2>Establishing Project</h2>
<p>Now create your first ramaze project with:</p>
<pre  name="code" class="ruby:nocontrols">
ramaze --create demo
</pre>
<p>Then change to the demo directory.  If you see a start.ru file, rename it to config.ru or Passenger won&#8217;t find it.  Create a file called passenger.rb with the following:</p>
<pre  name="code" class="ruby:nocontrols">
require 'rubygems'
require 'ramaze'

# Add directory start.rb is in to the load path, so you can run the app from
# any other working path
$LOAD_PATH.unshift(__DIR__)

# Initialize controllers and models
require 'controller/init'
require 'model/init'

Ramaze::Global.sourcereload = false
Ramaze::Global.sessions = true
Ramaze::Log.ignored_tags = [:debug, :info]
</pre>
<p>Important:  Do not include &#8220;Ramaze.start &#8230;&#8221; in this file or this will surely mess things up for Passenger.</p>
<p>Now edit the config.ru file (formerly start.ru):</p>
<pre  name="code" class="ruby:nocontrols">
/usr/bin/env rackup
# start.ru for ramaze apps
# use thin>=0.6.3
# thin start -r start.ru
#
# rackup is a useful tool for running Rack applications, which uses the
# Rack::Builder DSL to configure middleware and build up applications easily.
#
# rackup automatically figures out the environment it is run in, and runs your
# application as FastCGI, CGI, or standalone with Mongrel or WEBrick�..all from
# the same configuration.

require 'app'
Ramaze.trait[:essentials].delete Ramaze::Adapter
Ramaze.start
run Ramaze::Adapter::Base
</pre>
<p>Add the following virtual host file to /etc/apache2/sites-enabled/001-ramaze-demo</p>
<pre  name="code" class="ruby:nocontrols">
&lt;VirtualHost *:80&gt;
    ServerName ramaze.demo.local
    RackBaseURI /
    RailsAutoDetect off
    RackAutoDetect on
    DocumentRoot /var/www/ramaze/demo/public
&lt;/VirtualHost&gt;
</pre>
<p>And edit your /etc/hosts file to include &#8220;ramaze.demo.local&#8221; so it resolves to localhost.</p>
<h2>Database</h2>
<p>Next, create a database called ramaze_demo (or your choice) and add a posts table and<br />
some data via SQL or migrate scripts (this being a minimal demonstration and all that).</p>
<pre  name="code" class="sql:nocontrols">
create table posts (
    id        int(11) not null auto_increment
  , title     varchar(255) not null
  , body      varchar(1024) not null
  , primary key (id)
);

insert posts values (1, "First Post", "Thank hrnt for getting passenger talking to ramaze.");
insert posts values (2, "Another Post", "Ask Pistos what SelfMarks is, because he is bored with diigo");
insert posts values (3, "IRC, you say?", "Visit #ramaze on Freenode");
</pre>
<p><H2>Model</h2>
<p>Edit the model.init.rb file with the following:</p>
<pre  name="code" class="ruby:nocontrols">
require 'activerecord'
require 'cleanup_connection_patch'

  ActiveRecord::Base.establish_connection(
    :adapter  => "mysql",
    :database => "ramaze_demo",
    :host     => "localhost",
    :username => "root",
    :password => "secret"
  )

class Post < ActiveRecord::Base
end
</pre>
<p>Important:  cleanup_connection_patch comes from <a href="http://github.com/coderrr/cleanup_connection/tree/master">github.com</a> and makes the ActiveRecord behave correctly in a threaded environment.  Please see <a href="http://coderrr.wordpress.com/2009/01/16/monkey-patching-activerecord-to-automatically-release-connections/">Monkey patching ActiveRecord to automatically release connections &laquo; coderrr</a> for more information.</p>
<h2>Controller</h2>
<p>With the model squared away, time to turn our attention to the controller.  Edit controller/init.rb:</p>
<pre  name="code" class="ruby:nocontrols">
class Controller < Ramaze::Controller
  layout '/page'
  helper <img src='http://ramblings.gibberishcode.net/wp-includes/images/smilies/icon_mad.gif' alt=':x' class='wp-smiley' /> html
  engine :Erubis
end

class PostsController < Controller
  def index
    @posts = Post.find(:all)
  end
end
</pre>
<h2>View</h2>
<p>Create a folder under view for posts and add the following Erubis template view/posts.rhtml:</p>
<pre  name="code" class="html:nocontrols">
&lt;h1&gt;Listing Posts&lt;/h1&gt;

&lt;ul&gt;
  &lt;% for post in @posts %&gt;
      &lt;li&gt;&lt;%= A(post.title, :href =&gt; "/post/#{post.id}", :title =&gt; post.body) %&gt;&lt;/li&gt;
  &lt;% end %&gt;
&lt;/ul&gt;
</pre>
<p>Note: that while Rails uses filename.html.erb, the Erubis engine expects *.rhtml extension in Ramaze.</p>
<h2>Running</h2>
<p>Test out the above with webrick, mongrel, or thin with:</p>
<pre  name="code" class="ruby:nocontrols">
ruby start.rb
</pre>
<p>If all goes well, you should see the three postings above listed.</p>
<p>Launch Apache2, if you haven't already and point your localhost's browser at http://ramaze.demo.local/posts</p>
<p>You should now have a listing of posts rendered through Apache via Passenger.</p>
<h2>Conclusion</h2>
<p>I am finding much to like about Ramaze, especially after developing with Rails for a few years now and watching it grow at an alarming rate in complexity.  Ramaze is a refreshing return to basics.  I am finding that Ramaze just may be able to give me most of what I need while giving me a sizeable performance boost in the process.  Here's a rails bench on the equivalent of the above:</p>
<pre style="overflow: hidden">
Concurrency Level:      50
Time taken for tests:   4.277 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      10218492 bytes
HTML transferred:       9595000 bytes
Requests per second:    233.83 [#/sec] (mean)
Time per request:       213.828 [ms] (mean)
Time per request:       4.277 [ms] (mean, across all concurrent requests)
Transfer rate:          2333.42 [Kbytes/sec] received
</pre>
<p>And this is Ramaze:</p>
<pre style="overflow: hidden">
Concurrency Level:      50
Time taken for tests:   2.248 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      9815000 bytes
HTML transferred:       9555000 bytes
Requests per second:    444.91 [#/sec] (mean)
Time per request:       112.383 [ms] (mean)
Time per request:       2.248 [ms] (mean, across all concurrent requests)
Transfer rate:          4264.42 [Kbytes/sec] received
</pre>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/ramaze-and-activerecord/26/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Initial release of Elemental</title>
		<link>http://ramblings.gibberishcode.net/archives/initial-release-of-elemental/25</link>
		<comments>http://ramblings.gibberishcode.net/archives/initial-release-of-elemental/25#comments</comments>
		<pubDate>Tue, 03 Feb 2009 00:57:34 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby Language]]></category>
		<category><![CDATA[announcement]]></category>
		<category><![CDATA[elemental]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=25</guid>
		<description><![CDATA[I am happy to announce the initial release of Elemental 0.1.1.
Elemental provides enumerated collection of elements that allow you to associate ruby symbols to arbitrary &#8220;display&#8221; values, thus allowing your code to think symbolically and unambiguously while giving you the means to easily display what end-users need to see. Additionally, symbols are associated with ordinal [...]]]></description>
			<content:encoded><![CDATA[<p>I am happy to announce the initial release of Elemental 0.1.1.</p>
<p>Elemental provides enumerated collection of elements that allow you to associate ruby symbols to arbitrary &#8220;display&#8221; values, thus allowing your code to think symbolically and unambiguously while giving you the means to easily display what end-users need to see. Additionally, symbols are associated with ordinal values, allowing easy storage/retrieval to persistent stores (databases, files, marshalling, etc) by saving the  Element#value as appropriate (String by default, Fixnum if you &#8220;persist_ordinally&#8221;).</p>
<p>The primary aim of Elemental is to collect and abstract literals away from your code logic. There&#8217;s an old programmer&#8217;s wisdom that you should not encode your logic using literal values, especially those the end-user is exposed to.</p>
<p>Complete details provided in README.txt</p>
<p>http://github.com/mwlang/elemental/tree/master</p>
<p>http://rubyforge.org/projects/elemental/</p>
<p>From Gem:</p>
<pre  name="code" class="ruby:nocontrols">
sudo gem install elemental
</pre>
<p>From Source:</p>
<pre  name="code" class="ruby:nocontrols">
gem install bones, rake, test-unit
git clone git://github.com/mwlang/elemental.git
cd elemental
rake gem:package
cd pkg
sudo gem install elemental
</pre>
<p>Example of Using:<br />
Here&#8217;s an example of how Elemental might be used with a Rails application.  In your ~/config/initializers/elementals.rb file:</p>
<pre  name="code" class="ruby:nocontrols">
require 'elemental'

class PublicStatus
  extend Elemental

  member :unpublished,      :display => "Not Published", :default => true
  member :editor_approval,  :display => "Editorial Approval Needed"
  member :published,        :display => "Published"
  member :archived,         :display => "Archived"
end

class CommentType
  extend Elemental
  persist_ordinally

  member :all,        :display => "Anyone can post"
  member :moderated,  :display => "Moderated", :default => true
  member :closed,     :display => "Closed to new posts"
end
</pre>
<p>Create a &#8220;posts&#8221; table with this migration:</p>
<pre  name="code" class="ruby:nocontrols">
class CreatePosts < ActiveRecord::Migration
  def self.up
    create_table :posts do |t|
      t.string :title
      t.text :body
      t.string :public_status
      t.integer :comment_type

      t.timestamps
    end
  end

  def self.down
    drop_table :posts
  end
end
</pre>
<p>In your ~/app/views/posts/edit.html.erb:</p>
<pre  name="code" class="html:nocontrols">
&lt;h1&gt;Editing post&lt;/h1&gt;

&lt;% form_for(@post) do |f| %&gt;
  &lt;%= f.error_messages %&gt;

  &lt;%= render :partial =&gt; 'form' %&gt;

  &lt;p&gt;
    &lt;%= f.submit "Update" %&gt;
  &lt;/p&gt;
&lt;% end %&gt;

&lt;%= link_to 'Show', @post %&gt; |
&lt;%= link_to 'Back', posts_path %&gt;
</pre>
<p>Similarly for ~/app/views/posts/new.html.erb</p>
<pre  name="code" class="html:nocontrols">
&lt;h1&gt;New post&lt;/h1&gt;

&lt;% form_for(@post) do |f| %&gt;
  &lt;%= f.error_messages %&gt;

	&lt;%= render :partial =&gt; 'form' %&gt;

  &lt;p&gt;
    &lt;%= f.submit "Create" %&gt;
  &lt;/p&gt;
&lt;% end %&gt;

&lt;%= link_to 'Back', posts_path %&gt;
</pre>
<p>An form partial that utilizes the Elemental classes above to populate a pair of drop down lists:</p>
<pre  name="code" class="html:nocontrols">
&lt;p&gt;
	&lt;label&gt;Title&lt;/label&gt;&lt;br /&gt;
	&lt;%= text_field :post, :title, :value =&gt; @post.title %&gt;
&lt;/p&gt;
&lt;p&gt;
	&lt;label&gt;Body&lt;/label&gt;&lt;br /&gt;
	&lt;%= text_area :post, :body, :value =&gt; @post.body %&gt;
&lt;/p&gt;

&lt;p&gt;&lt;label&gt;Public Status&lt;/label&gt;&lt;br /&gt;
  &lt;%= select "post", "public_status",
    PublicStatus.sort.map{|a| [a.display, a.value]},
      { :include_blank =&gt; false, :selected =&gt; PublicStatus.defaults.first.value }
  %&gt;&lt;/select&gt;
&lt;/p&gt;

&lt;p&gt;&lt;label&gt;Comment Type&lt;/label&gt;&lt;br /&gt;
  &lt;%= select "post", "comment_type",
    CommentType.sort.map{|a| [a.display, a.value]},
      { :include_blank =&gt; false, :selected =&gt; CommentType.defaults.first.value }
  %&gt;&lt;/select&gt;
&lt;/p&gt;
</pre>
<p>An example ~/app/views/posts/index.html.erb file:</p>
<pre  name="code" class="html:nocontrols">
&lt;h1&gt;Listing posts&lt;/h1&gt;

&lt;table border=1 cellpadding=5px&gt;
  &lt;tr&gt;
    &lt;th&gt;Post&lt;/th&gt;
    &lt;th&gt;Public status&lt;/th&gt;
    &lt;th&gt;Comment type&lt;/th&gt;
    &lt;th colspan=3&gt;Actions&lt;/th&gt;
  &lt;/tr&gt;

&lt;% for post in @posts %&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;%= link_to post.title, post, :title =&gt; post.body %&gt;&lt;/td&gt;
    &lt;td&gt;&lt;%=h PublicStatus[post.public_status].display %&gt;&lt;/td&gt;
    &lt;td&gt;&lt;%=h CommentType[post.comment_type].display %&gt;&lt;/td&gt;
    &lt;td&gt;&lt;%= link_to 'Show', post %&gt;&lt;/td&gt;
    &lt;td&gt;&lt;%= link_to 'Edit', edit_post_path(post) %&gt;&lt;/td&gt;
    &lt;td&gt;&lt;%= link_to 'Destroy', post, :confirm =&gt; 'Are you sure?', :method =&gt; :delete %&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;% end %&gt;
&lt;/table&gt;

&lt;br /&gt;

&lt;%= link_to 'New post', new_post_path %&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/initial-release-of-elemental/25/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby, Mysql, CentOS 5, and 64-bit</title>
		<link>http://ramblings.gibberishcode.net/archives/ruby-mysql-centos-5-and-64-bit/23</link>
		<comments>http://ramblings.gibberishcode.net/archives/ruby-mysql-centos-5-and-64-bit/23#comments</comments>
		<pubDate>Mon, 19 Jan 2009 20:36:35 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Systems]]></category>
		<category><![CDATA[64-bit]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[Ruby Language]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=23</guid>
		<description><![CDATA[I have lately switched away from Ubuntu as my desktop and started using CentOS 5.2 because I wanted better support for a lot of RAM and virtualization (where I can quickly commission Linux servers to build out my testbed of target environments).  With the change, I also make the leap into pure 64-bit libraries with [...]]]></description>
			<content:encoded><![CDATA[<p>I have lately switched away from Ubuntu as my desktop and started using CentOS 5.2 because I wanted better support for a lot of RAM and virtualization (where I can quickly commission Linux servers to build out my testbed of target environments).  With the change, I also make the leap into pure 64-bit libraries with little to no 32-bit libraries installed.  There&#8217;s been a few sticky points to push through and one of them is getting Mysql and the appropriate mysql gems installed.  This quick post shows the way.</p>
<p><H2>My System</H2><br />
I am running CentOS 5.2 64-bit.  Or more succinctly:</p>
<pre  name="code" class="c:nocontrols">
2.6.18-92.1.22.el5 #1 SMP Tue Dec 16 11:57:43 EST 2008 x86_64 x86_64 x86_64 GNU/Linux
</pre>
<h2>The Problem</h2>
<p>If you simply execute:</p>
<pre  name="code" class="c:nocontrols">
sudo gem install mysql
</pre>
<p>You&#8217;ll get the following errors on a 64-bit system:</p>
<pre  name="code" class="c:nocontrols">
$ sudo gem install mysql
Building native extensions.  This could take a while...
ERROR:  Error installing mysql:
        ERROR: Failed to build gem native extension.

/usr/local/bin/ruby extconf.rb install mysql
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lm... yes
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lz... yes
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lsocket... no
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lnsl... yes
checking for mysql_query() in -lmysqlclient... no
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers.  Check the mkmf.log file for more
details.  You may need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=/usr/local/bin/ruby
        --with-mysql-config
        --without-mysql-config
        --with-mysql-dir
        --without-mysql-dir
        --with-mysql-include
        --without-mysql-include=${mysql-dir}/include
        --with-mysql-lib
        --without-mysql-lib=${mysql-dir}/lib
        --with-mysqlclientlib
        --without-mysqlclientlib
        --with-mlib
        --without-mlib
        --with-mysqlclientlib
        --without-mysqlclientlib
        --with-zlib
        --without-zlib
        --with-mysqlclientlib
        --without-mysqlclientlib
        --with-socketlib
        --without-socketlib
        --with-mysqlclientlib
        --without-mysqlclientlib
        --with-nsllib
        --without-nsllib
        --with-mysqlclientlib
        --without-mysqlclientlib

Gem files will remain installed in /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7 for inspection.
Results logged to /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7/gem_make.out
</pre>
<p>After digging into the gem options and logs a bit and looking at where mysql actually got installed, I discovered that it was hitting all the locations the 32-bit version would normally install to, but not the 64-bit version, which ends up in /usr/lib64/mysql. </p>
<p><H2>Installing the Ruby gems</h2>
<p>To properly install the Ruby gems for mysql, you&#8217;ll have to explicitly tell the gem where the mysql config is and it will then handle all the rest.  </p>
<pre  name="code" class="c:nocontrols">
gem install mysql -- --with-mysql-config=/usr/lib64/mysql/mysql_config
</pre>
<p>With that, you should see the following:</p>
<pre  name="code" class="c:nocontrols">
Building native extensions.  This could take a while...
Successfully installed mysql-2.7
1 gem installed
</pre>
<p>Check it out with:</p>
<pre  name="code" class="c:nocontrols">
irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'mysql'
=> true
irb(main):003:0> quit
</pre>
<p>Life is good.  </p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/ruby-mysql-centos-5-and-64-bit/23/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Rails has and belongs to many (habtm) demystified</title>
		<link>http://ramblings.gibberishcode.net/archives/rails-has-and-belongs-to-many-habtm-demystified/17</link>
		<comments>http://ramblings.gibberishcode.net/archives/rails-has-and-belongs-to-many-habtm-demystified/17#comments</comments>
		<pubDate>Mon, 27 Oct 2008 14:49:02 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby Language]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[many-to-many]]></category>
		<category><![CDATA[rails]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=17</guid>
		<description><![CDATA[Every time I have to implement a many-to-many relationship between Rails models, I seem to have to figure out how to do it effectively all over again.  Especially as Rails seems to evolve the relational hooks with better support and elegance.  Here, I will show a has_and_belongs_to_many strategy that works well for me.  Along the way, I'll expose a few other minor tricks, such as adding a custom inflector for pluralizing your model or not adding the ID column on a table declaration.]]></description>
			<content:encoded><![CDATA[<p>Every time I have to implement a many-to-many relationship between Rails models, I seem to have to figure out how to do it effectively all over again.  Especially as Rails seems to evolve the relational hooks with better support and elegance.  Here, I will show a has_and_belongs_to_many strategy that works well for me.  Along the way, I&#8217;ll expose a few other minor tricks, such as adding a custom inflector for pluralizing your model or not adding the ID column on a table declaration.</p>
<p>The following Browser Edit form is what we&#8217;re going for.  That is, having a list of Operating Systems to check off while editing a Browser object:</p>
<p><center><br />
<img src="http://ramblings.gibberishcode.net/wp-content/uploads/2008/10/editing_browser.png" alt="Editing Browser View" title="editing_browser" width="266" height="453" class="alignleft size-full wp-image-18" /><br />
</center><br />
First, the models:  What I wanted, was a way to declare browsers (Firefox, Explorer, Opera, etc.) and associate them with one or more operating systems (OS X, Windows, Linux, etc.).  This begats two models, <strong>Os</strong>, and <strong>Browser</strong> with a many-to-many table, <strong>browsers_oses</strong> joining the two.  The migration scripts for these models follow:</p>
<pre class="twilight"><span class="Keyword">class</span> <span class="Entity">CreateBrowsers<span class="EntityInheritedClass"> <span class="EntityInheritedClass">&lt;</span> ActiveRecord::Migration</span></span>
  <span class="Keyword">def</span> <span class="Entity">self.up</span>
    create_table <span class="Constant"><span class="Constant">:</span>browsers</span> <span class="Keyword">do </span>|<span class="Variable">t</span>|
      t.<span class="Entity">string</span> <span class="Constant"><span class="Constant">:</span>name</span>
      t.<span class="Entity">string</span> <span class="Constant"><span class="Constant">:</span>version</span>
      t.<span class="Entity">string</span> <span class="Constant"><span class="Constant">:</span>short_name</span>
      t.<span class="Entity">timestamps</span>
    <span class="Keyword">end</span>
  <span class="Keyword">end</span>

  <span class="Keyword">def</span> <span class="Entity">self.down</span>
    drop_table <span class="Constant"><span class="Constant">:</span>browsers</span>
  <span class="Keyword">end</span>
<span class="Keyword">end</span>
</pre>
<pre class="twilight"><span class="Keyword">class</span> <span class="Entity">CreateOses<span class="EntityInheritedClass"> <span class="EntityInheritedClass">&lt;</span> ActiveRecord::Migration</span></span>
  <span class="Keyword">def</span> <span class="Entity">self.up</span>
    create_table <span class="Constant"><span class="Constant">:</span>oses</span> <span class="Keyword">do </span>|<span class="Variable">t</span>|
      t.<span class="Entity">string</span> <span class="Constant"><span class="Constant">:</span>vendor</span>
      t.<span class="Entity">string</span> <span class="Constant"><span class="Constant">:</span>name</span>
      t.<span class="Entity">string</span> <span class="Constant"><span class="Constant">:</span>version</span>
      t.<span class="Entity">string</span> <span class="Constant"><span class="Constant">:</span>short_name</span>
      t.<span class="Entity">timestamps</span>
    <span class="Keyword">end</span>
  <span class="Keyword">end</span>

  <span class="Keyword">def</span> <span class="Entity">self.down</span>
    drop_table <span class="Constant"><span class="Constant">:</span>oses</span>
  <span class="Keyword">end</span>
<span class="Keyword">end</span>
</pre>
<p>The Browser and Os table are very straightforward migration scripts.  However, pay attention to the next script as we do a couple of interesting things.  A) we tell the migration not to create the default ID column and B) we use the t.references declaration in defining our columns.</p>
<pre class="twilight"><span class="Keyword">class</span> <span class="Entity">BrowsersOses<span class="EntityInheritedClass"> <span class="EntityInheritedClass">&lt;</span> ActiveRecord::Migration</span></span>
  <span class="Keyword">def</span> <span class="Entity">self.up</span>
      create_table <span class="Constant"><span class="Constant">:</span>browsers_oses</span>, <span class="Constant"><span class="Constant">:</span>id</span> =&gt; <span class="Constant">false</span> <span class="Keyword">do </span>|<span class="Variable">t</span>|
        t.<span class="Entity">references</span> <span class="Constant"><span class="Constant">:</span>browser</span>
        t.<span class="Entity">references</span> <span class="Constant"><span class="Constant">:</span>os</span>
        t.<span class="Entity">timestamps</span>
      <span class="Keyword">end</span>
    <span class="Keyword">end</span>

    <span class="Keyword">def</span> <span class="Entity">self.down</span>
      drop_table <span class="Constant"><span class="Constant">:</span>browsers_oses</span>
  <span class="Keyword">end</span>
<span class="Keyword">end</span>
</pre>
<p>Note that I used the singular version of the model names.  I originally used the plural form and got <strong>browsers_id</strong> and <strong>oses_id</strong> instead of the expected <strong>browser_id</strong> and <strong>os_id</strong> column names.</p>
<p>Which brings me to another issue I encountered.  &#8220;Os&#8221; didn&#8217;t pluralize properly, so I needed to add a custom inflector to the project&#8217;s <strong>config/initializers/inflections.rb</strong> file:</p>
<pre class="twilight"><span class="Support">ActiveSupport</span>::<span class="Entity">Inflector</span>.<span class="Entity">inflections</span> <span class="Keyword">do </span>|<span class="Variable">inflect</span>|
  inflect.<span class="Entity">irregular</span> <span class="String"><span class="String">'</span>os<span class="String">'</span></span>, <span class="String"><span class="String">'</span>oses<span class="String">'</span></span>
<span class="Keyword">end</span>
</pre>
<p>For simplicity and clarity, I chose the irregular form since I didn&#8217;t figure on needing to match regular expressions against more complex model names.</p>
<p>Since there are many articles dedicated to the model side of things where relationships are concerned, I will skimp on discussing model implementations.  Please see <a href="http://blog.hasmanythrough.com/2006/4/20/many-to-many-dance-off">many-to-many-dance-off</a> by Josh Susser or the <a href="http://wiki.rubyonrails.org/rails/pages/has_and_belongs_to_many">has_and_belongs_to_many</a> page on the Ruby on Rails wiki site for a couple of classics on the topic.</p>
<p>The models are straightforward, as shown below.  Note that the <strong>browsers_oses</strong> table does not get its own model.  Rails simply expects the table to be a concatenation of the two models pluralized and the model names in alphabetical order.</p>
<pre class="twilight"><span class="Keyword">class</span> <span class="Entity">Os<span class="EntityInheritedClass"> <span class="EntityInheritedClass">&lt;</span> ActiveRecord::Base</span></span>
  has_and_belongs_to_many <span class="Constant"><span class="Constant">:</span>browsers</span>
<span class="Keyword">end</span>

<span class="Keyword">class</span> <span class="Entity">Browser<span class="EntityInheritedClass"> <span class="EntityInheritedClass">&lt;</span> ActiveRecord::Base</span></span>
  has_and_belongs_to_many <span class="Constant"><span class="Constant">:</span>oses</span>
<span class="Keyword">end</span>
</pre>
<p>I&#8217;m not a big fan of the default views the rails scaffolding produces, but I do tend to run <em>script/generate scaffold &#8220;model_name&#8221;</em> to get the ball rolling quickly, anyway.  So fire up a couple of views with:</p>
<pre class="twilight">script/generate scaffold browser
script/generate scaffold os
</pre>
<p><strong>Note:</strong>  I removed all previously generated files and regenerated the <strong>Os</strong> model and views after adding the irregular plural inflection rule described above.</p>
<p>Once I get my models and views, the first thing I do is create a form partial for each:</p>
<p><strong>app/views/oses/_form.html.erb</strong></p>
<pre class="twilight"><span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">fieldset</span><span class="MetaTagAll">&gt;</span></span>
	<span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">legend</span><span class="MetaTagInline">&gt;</span></span>OS<span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">legend</span><span class="MetaTagInline">&gt;</span></span>
	<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>
		<span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">label</span> <span class="MetaTagInline">for</span>=<span class="String"><span class="String">&quot;</span>vendor<span class="String">&quot;</span></span><span class="MetaTagInline">&gt;</span></span>Vendor<span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">label</span><span class="MetaTagInline">&gt;</span></span>
		<span class="EmbeddedSource"><span class="EmbeddedSource">&lt;%=</span> text_field <span class="Constant"><span class="Constant">:</span>os</span><span class="EmbeddedSource">,</span> <span class="Constant"><span class="Constant">:</span>vendor</span><span class="EmbeddedSource">,</span> <span class="Constant"><span class="Constant">:</span>value</span> <span class="EmbeddedSource">=&gt;</span> <span class="Variable"><span class="Variable">@</span>os</span><span class="EmbeddedSource"><span class="EmbeddedSource">.</span><span class="Entity">vendor</span></span> <span class="EmbeddedSource">%&gt;</span></span>
	<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>

	<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>
		<span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">label</span> <span class="MetaTagInline">for</span>=<span class="String"><span class="String">&quot;</span>name<span class="String">&quot;</span></span><span class="MetaTagInline">&gt;</span></span>Name<span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">label</span><span class="MetaTagInline">&gt;</span></span>
		<span class="EmbeddedSource"><span class="EmbeddedSource">&lt;%=</span> text_field <span class="Constant"><span class="Constant">:</span>os</span><span class="EmbeddedSource">,</span> <span class="Constant"><span class="Constant">:</span>name</span><span class="EmbeddedSource">,</span> <span class="Constant"><span class="Constant">:</span>value</span> <span class="EmbeddedSource">=&gt;</span> <span class="Variable"><span class="Variable">@</span>os</span><span class="EmbeddedSource"><span class="EmbeddedSource">.</span><span class="Entity">name</span></span> <span class="EmbeddedSource">%&gt;</span></span>
	<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>

	<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>
		<span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">label</span> <span class="MetaTagInline">for</span>=<span class="String"><span class="String">&quot;</span>version<span class="String">&quot;</span></span><span class="MetaTagInline">&gt;</span></span>Version<span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">label</span><span class="MetaTagInline">&gt;</span></span>
		<span class="EmbeddedSource"><span class="EmbeddedSource">&lt;%=</span> text_field <span class="Constant"><span class="Constant">:</span>os</span><span class="EmbeddedSource">,</span> <span class="Constant"><span class="Constant">:</span>version</span><span class="EmbeddedSource">,</span> <span class="Constant"><span class="Constant">:</span>value</span> <span class="EmbeddedSource">=&gt;</span> <span class="Variable"><span class="Variable">@</span>os</span><span class="EmbeddedSource"><span class="EmbeddedSource">.</span><span class="Entity">version</span></span> <span class="EmbeddedSource">%&gt;</span></span>
	<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>

	<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>
		<span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">label</span> <span class="MetaTagInline">for</span>=<span class="String"><span class="String">&quot;</span>short_name<span class="String">&quot;</span></span><span class="MetaTagInline">&gt;</span></span>Short Name<span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">label</span><span class="MetaTagInline">&gt;</span></span>
		<span class="EmbeddedSource"><span class="EmbeddedSource">&lt;%=</span> text_field <span class="Constant"><span class="Constant">:</span>os</span><span class="EmbeddedSource">,</span> <span class="Constant"><span class="Constant">:</span>short_name</span><span class="EmbeddedSource">,</span> <span class="Constant"><span class="Constant">:</span>value</span> <span class="EmbeddedSource">=&gt;</span> <span class="Variable"><span class="Variable">@</span>os</span><span class="EmbeddedSource"><span class="EmbeddedSource">.</span><span class="Entity">short_name</span></span> <span class="EmbeddedSource">%&gt;</span></span>
	<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>
<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">fieldset</span><span class="MetaTagAll">&gt;</span></span>
</pre>
<p>There&#8217;s nothing fancy about the <strong>Os</strong> form as there&#8217;s no references to select drop-downs or the likes.  With the above wrapped in a fieldset with legend of <strong>Os</strong>. I then  tweak <strong>app/views/oses/edit.html.erb</strong> like so:</p>
<pre class="twilight"><span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">h1</span><span class="MetaTagAll">&gt;</span></span>Editing OS<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">h1</span><span class="MetaTagAll">&gt;</span></span>

<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%</span> <span class="EmbeddedSourceBright"><span class="Entity">form_for</span></span><span class="EmbeddedSourceBright">(</span><span class="Variable"><span class="Variable">@</span>os</span><span class="EmbeddedSourceBright">)</span> <span class="Keyword">do </span><span class="EmbeddedSourceBright">|</span><span class="Variable">f</span><span class="EmbeddedSourceBright">|</span> <span class="EmbeddedSourceBright">%&gt;</span></span>
  	<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> f<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">error_messages</span></span> <span class="EmbeddedSourceBright">%&gt;</span></span>
	<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> <span class="SupportFunction">render</span> <span class="Constant"><span class="Constant">:</span>partial</span> <span class="EmbeddedSourceBright">=&gt;</span> <span class="String"><span class="String">'</span>form<span class="String">'</span></span> <span class="EmbeddedSourceBright">%&gt;</span></span>

	<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">fieldset</span><span class="MetaTagAll">&gt;</span></span>
    	<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> f<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">submit</span></span> <span class="String"><span class="String">&quot;</span>Update<span class="String">&quot;</span></span> <span class="EmbeddedSourceBright">%&gt;</span></span>
		<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> link_to <span class="String"><span class="String">'</span>Show<span class="String">'</span></span><span class="EmbeddedSourceBright">,</span> <span class="Variable"><span class="Variable">@</span>os</span> <span class="EmbeddedSourceBright">%&gt;</span></span> |
		<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> link_to <span class="String"><span class="String">'</span>Back<span class="String">'</span></span><span class="EmbeddedSourceBright">,</span> oses_path <span class="EmbeddedSourceBright">%&gt;</span></span>
  	<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">fieldset</span><span class="MetaTagAll">&gt;</span></span>
<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%</span> <span class="Keyword">end</span> <span class="EmbeddedSourceBright">%&gt;</span></span>
</pre>
<p>And similarly for <strong>app/views/oses/new.html.erb</strong>:</p>
<pre class="twilight"><span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">h1</span><span class="MetaTagAll">&gt;</span></span>New OS<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">h1</span><span class="MetaTagAll">&gt;</span></span>

<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%</span> <span class="EmbeddedSourceBright"><span class="Entity">form_for</span></span><span class="EmbeddedSourceBright">(</span><span class="Variable"><span class="Variable">@</span>os</span><span class="EmbeddedSourceBright">)</span> <span class="Keyword">do </span><span class="EmbeddedSourceBright">|</span><span class="Variable">f</span><span class="EmbeddedSourceBright">|</span> <span class="EmbeddedSourceBright">%&gt;</span></span>
  	<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> f<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">error_messages</span></span> <span class="EmbeddedSourceBright">%&gt;</span></span>
	<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> <span class="SupportFunction">render</span> <span class="Constant"><span class="Constant">:</span>partial</span> <span class="EmbeddedSourceBright">=&gt;</span> <span class="String"><span class="String">'</span>form<span class="String">'</span></span> <span class="EmbeddedSourceBright">%&gt;</span></span>

  	<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">fieldset</span><span class="MetaTagAll">&gt;</span></span>
    	<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> f<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">submit</span></span> <span class="String"><span class="String">&quot;</span>Create<span class="String">&quot;</span></span> <span class="EmbeddedSourceBright">%&gt;</span></span>
		<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> link_to <span class="String"><span class="String">'</span>Back<span class="String">'</span></span><span class="EmbeddedSourceBright">,</span> oses_path <span class="EmbeddedSourceBright">%&gt;</span></span>
  	<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">fieldset</span><span class="MetaTagAll">&gt;</span></span>
<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%</span> <span class="Keyword">end</span> <span class="EmbeddedSourceBright">%&gt;</span></span>
</pre>
<p><strong>app/views/oses/show.html.erb</strong> is nearly a cut-n-paste of the _form.html.erb file with the input tags stripped out:</p>
<pre class="twilight"><span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">fieldset</span><span class="MetaTagAll">&gt;</span></span>
	<span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">legend</span><span class="MetaTagInline">&gt;</span></span>OS<span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">legend</span><span class="MetaTagInline">&gt;</span></span>
	<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>
		<span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">label</span> <span class="MetaTagInline">for</span>=<span class="String"><span class="String">&quot;</span>vendor<span class="String">&quot;</span></span><span class="MetaTagInline">&gt;</span></span>Vendor<span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">label</span><span class="MetaTagInline">&gt;</span></span>
		<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> <span class="Variable"><span class="Variable">@</span>os</span><span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">vendor</span></span> <span class="EmbeddedSourceBright">%&gt;</span></span>
	<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>

	<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>
		<span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">label</span> <span class="MetaTagInline">for</span>=<span class="String"><span class="String">&quot;</span>name<span class="String">&quot;</span></span><span class="MetaTagInline">&gt;</span></span>Name<span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">label</span><span class="MetaTagInline">&gt;</span></span>
		<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> <span class="Variable"><span class="Variable">@</span>os</span><span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">name</span></span> <span class="EmbeddedSourceBright">%&gt;</span></span>
	<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>

	<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>
		<span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">label</span> <span class="MetaTagInline">for</span>=<span class="String"><span class="String">&quot;</span>version<span class="String">&quot;</span></span><span class="MetaTagInline">&gt;</span></span>Version<span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">label</span><span class="MetaTagInline">&gt;</span></span>
		<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> <span class="Variable"><span class="Variable">@</span>os</span><span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">version</span></span> <span class="EmbeddedSourceBright">%&gt;</span></span>
	<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>

	<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>
		<span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">label</span> <span class="MetaTagInline">for</span>=<span class="String"><span class="String">&quot;</span>short_name<span class="String">&quot;</span></span><span class="MetaTagInline">&gt;</span></span>Short Name<span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">label</span><span class="MetaTagInline">&gt;</span></span>
		<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> <span class="Variable"><span class="Variable">@</span>os</span><span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">short_name</span></span> <span class="EmbeddedSourceBright">%&gt;</span></span>
	<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>
<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">fieldset</span><span class="MetaTagAll">&gt;</span></span>

<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">fieldset</span><span class="MetaTagAll">&gt;</span></span>
	<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> link_to <span class="String"><span class="String">'</span>Edit<span class="String">'</span></span><span class="EmbeddedSourceBright">,</span> <span class="EmbeddedSourceBright"><span class="Entity">edit_os_path</span></span><span class="EmbeddedSourceBright">(</span><span class="Variable"><span class="Variable">@</span>os</span><span class="EmbeddedSourceBright">)</span> <span class="EmbeddedSourceBright">%&gt;</span></span> |
	<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> link_to <span class="String"><span class="String">'</span>Back<span class="String">'</span></span><span class="EmbeddedSourceBright">,</span> oses_path <span class="EmbeddedSourceBright">%&gt;</span></span>
<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">fieldset</span><span class="MetaTagAll">&gt;</span></span>
</pre>
<p>It would be nice if the tag fields were action aware and intelligently generated inputs or text rendering according to whether new, edit, or show was the action, wouldn&#8217;t it??</p>
<p>The <strong>OsesController</strong> model is unchanged from the generated scaffolding code, so I won&#8217;t list its code here.  Lets hop over to Browsers model and view as this is the model I do the most interesting things with.  I will be rendering the Browser inputs so that one of the input is a checkbox list of all available OSes.  To do this, I am effectively performing a &#8220;find all&#8221; on the Os model, so I DRY my code by adding the following method to the <strong>BrowsersController</strong>:</p>
<pre class="twilight"><span class="Keyword">def</span> <span class="Entity">get_all_oses</span>
  <span class="Variable"><span class="Variable">@</span>oses</span> <span class="Keyword">=</span> <span class="Support">Os</span>.<span class="Entity">find</span>(<span class="Constant"><span class="Constant">:</span>all</span>, <span class="Constant"><span class="Constant">:</span>order</span> =&gt; <span class="String"><span class="String">'</span>vendor, version<span class="String">'</span></span>)
<span class="Keyword">end</span>
</pre>
<p>Declaring small, single purpose methods is a good practice to be in the habit of.  As it happened, I decided at some point to order the checklist by vendor and version.  Instead of having to change code in four or five methods, I only had to update the one <strong>get_all_oses</strong> method.  A tad bit of extra work up front pays off!</p>
<p>Similarly, compound names get their own method in the model class so I have ability to easily change without hunting down references everywhere in the view.  So the Os model presented above becomes:</p>
<pre class="twilight"><span class="Keyword">class</span> <span class="Entity">Os<span class="EntityInheritedClass"> <span class="EntityInheritedClass">&lt;</span> ActiveRecord::Base</span></span>
  has_and_belongs_to_many <span class="Constant"><span class="Constant">:</span>browsers</span>

  <span class="Keyword">def</span> <span class="Entity">display_name</span>
    <span class="String"><span class="String">&quot;</span><span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>vendor<span class="StringEmbeddedSource">}</span></span> <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>name<span class="StringEmbeddedSource">}</span></span> <span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>version<span class="StringEmbeddedSource">}</span></span><span class="String">&quot;</span></span>
  <span class="Keyword">end</span>
<span class="Keyword">end</span>
</pre>
<p>And then I reference like so in the Browser view&#8217;s form partial:</p>
<pre class="twilight"><span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">fieldset</span><span class="MetaTagAll">&gt;</span></span>
	<span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">legend</span><span class="MetaTagInline">&gt;</span></span>Browser<span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">legend</span><span class="MetaTagInline">&gt;</span></span>
	<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>
		<span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">label</span> <span class="MetaTagInline">for</span>=<span class="String"><span class="String">&quot;</span>name<span class="String">&quot;</span></span><span class="MetaTagInline">&gt;</span></span>Name<span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">label</span><span class="MetaTagInline">&gt;</span></span>
		<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> text_field <span class="Constant"><span class="Constant">:</span>browser</span><span class="EmbeddedSourceBright">,</span> <span class="Constant"><span class="Constant">:</span>name</span><span class="EmbeddedSourceBright">,</span> <span class="Constant"><span class="Constant">:</span>value</span> <span class="EmbeddedSourceBright">=&gt;</span> <span class="Variable"><span class="Variable">@</span>browser</span><span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">name</span></span> <span class="EmbeddedSourceBright">%&gt;</span></span>
	<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>

	<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>
		<span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">label</span> <span class="MetaTagInline">for</span>=<span class="String"><span class="String">&quot;</span>version<span class="String">&quot;</span></span><span class="MetaTagInline">&gt;</span></span>Version<span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">label</span><span class="MetaTagInline">&gt;</span></span>
		<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> text_field <span class="Constant"><span class="Constant">:</span>browser</span><span class="EmbeddedSourceBright">,</span> <span class="Constant"><span class="Constant">:</span>version</span><span class="EmbeddedSourceBright">,</span> <span class="Constant"><span class="Constant">:</span>value</span> <span class="EmbeddedSourceBright">=&gt;</span> <span class="Variable"><span class="Variable">@</span>browser</span><span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">version</span></span> <span class="EmbeddedSourceBright">%&gt;</span></span>
	<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>

	<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>
		<span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">label</span> <span class="MetaTagInline">for</span>=<span class="String"><span class="String">&quot;</span>oses<span class="String">&quot;</span></span><span class="MetaTagInline">&gt;</span></span>Operating Systems<span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">label</span><span class="MetaTagInline">&gt;</span></span>
		<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%</span> <span class="Variable"><span class="Variable">@</span>oses</span><span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">each</span></span> <span class="Keyword">do </span><span class="EmbeddedSourceBright">|</span><span class="Variable">os</span><span class="EmbeddedSourceBright">|</span> <span class="EmbeddedSourceBright">%&gt;</span></span>
			<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> <span class="EmbeddedSourceBright"><span class="Entity">check_box_tag</span></span><span class="EmbeddedSourceBright">(</span></span>
<span class="EmbeddedSourceBright">                            <span class="String"><span class="String">&quot;</span>browser[os_list][<span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>os<span class="StringEmbeddedSource"><span class="StringEmbeddedSource">.</span><span class="Entity">id</span></span><span class="StringEmbeddedSource">}</span></span>]<span class="String">&quot;</span></span><span class="EmbeddedSourceBright">,</span> </span>
<span class="EmbeddedSourceBright">                            <span class="String"><span class="String">&quot;</span>1<span class="String">&quot;</span></span><span class="EmbeddedSourceBright">,</span> </span>
<span class="EmbeddedSourceBright">                            <span class="Variable"><span class="Variable">@</span>browser</span><span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">oses</span></span><span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">detect</span></span><span class="EmbeddedSourceBright">{</span><span class="EmbeddedSourceBright">|</span><span class="Variable">d</span><span class="EmbeddedSourceBright">|</span> d <span class="Keyword">==</span> os<span class="EmbeddedSourceBright">}</span><span class="EmbeddedSourceBright">)</span> <span class="EmbeddedSourceBright">%&gt;</span></span>
			<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> <span class="String"><span class="String">&quot;</span><span class="StringEmbeddedSource"><span class="StringEmbeddedSource">#{</span>os<span class="StringEmbeddedSource"><span class="StringEmbeddedSource">.</span><span class="Entity">display_name</span></span><span class="StringEmbeddedSource">}</span></span><span class="String">&quot;</span></span><span class="EmbeddedSourceBright">%&gt;</span></span><span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">br</span> /<span class="MetaTagInline">&gt;</span></span>
		<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%</span> <span class="Keyword">end</span> <span class="EmbeddedSourceBright">%&gt;</span></span>
	<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>

	<span class="MetaTagAll"><span class="MetaTagAll">&lt;</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>
		<span class="MetaTagInline"><span class="MetaTagInline">&lt;</span><span class="MetaTagInline">label</span> <span class="MetaTagInline">for</span>=<span class="String"><span class="String">&quot;</span>short_name<span class="String">&quot;</span></span><span class="MetaTagInline">&gt;</span></span>Short Name<span class="MetaTagInline"><span class="MetaTagInline">&lt;/</span><span class="MetaTagInline">label</span><span class="MetaTagInline">&gt;</span></span>
		<span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">&lt;%=</span> text_field <span class="Constant"><span class="Constant">:</span>browser</span><span class="EmbeddedSourceBright">,</span> <span class="Constant"><span class="Constant">:</span>short_name</span><span class="EmbeddedSourceBright">,</span> <span class="Constant"><span class="Constant">:</span>value</span> <span class="EmbeddedSourceBright">=&gt;</span> <span class="Variable"><span class="Variable">@</span>browser</span><span class="EmbeddedSourceBright"><span class="EmbeddedSourceBright">.</span><span class="Entity">short_name</span></span> <span class="EmbeddedSourceBright">%&gt;</span></span>
	<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">p</span><span class="MetaTagAll">&gt;</span></span>
<span class="MetaTagAll"><span class="MetaTagAll">&lt;/</span><span class="MetaTagAll">fieldset</span><span class="MetaTagAll">&gt;</span></span>
</pre>
<p>A few important things to note here about the Operating Systems checklist:</p>
<ul>
<li>the @oses variable is a list of all Oses as per the get_all_oses method.</li>
<li>I gave the checkbox name &#8220;browser[os_list][#{os.id}]&#8221; which causes the params to collect all checkboxes into an &#8220;os_list&#8221; hash that is contained in the browser keyword on the params hash.  Keep this in mind because we&#8217;re going to leverage this in a moment.</li>
<li>I don&#8217;t do anything with the values of the checkbox, so the value assigned (&#8220;1&#8243; in this case) is of little concern.</li>
<li>The <strong>@browsers.oses.detect{|d| d == os}</strong> line activates the checkbox if the browser already has the Os associated with it.  (quite important for edit actions).</li>
</ul>
<p>So the Operating Systems checklist is simply an iteration over all OSes, emitting a checkbox input control for each and setting the checked flag accordingly.  So how do we handle this in the controller?  We don&#8217;t!  That&#8217;s right.  Not in the controller, but in the model.  This is &#8220;The Rails Way&#8221; as described in the Skinny Controller, Fat Model approaches championed by <a href="http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model">Jamis Buck</a> and <a href="http://www.therailsway.com/tags/model">The Rails Way</a> crew. My approach is to add a attribute accessor called &#8220;os_list&#8221; to the Browser model and a callback to the after_save event.  So the Browser model now becomes:</p>
<pre class="twilight"><span class="Keyword">class</span> <span class="Entity">Browser<span class="EntityInheritedClass"> <span class="EntityInheritedClass">&lt;</span> ActiveRecord::Base</span></span>
  has_and_belongs_to_many <span class="Constant"><span class="Constant">:</span>oses</span>

  <span class="Keyword">attr_accessor</span> <span class="Constant"><span class="Constant">:</span>os_list</span>
  after_save <span class="Constant"><span class="Constant">:</span>update_oses</span>

  <span class="Keyword">private</span> 

  <span class="Keyword">def</span> <span class="Entity">update_oses</span>
    oses.<span class="Entity">delete_all</span>
    selected_oses <span class="Keyword">=</span> os_list.<span class="Entity">nil?</span> <span class="Keyword">?</span> [] : os_list.<span class="Entity">keys</span>.<span class="Entity">collect</span>{|<span class="Variable">id</span>| <span class="Support">Os</span>.<span class="Entity">find_by_id</span>(id)}
    selected_oses.<span class="Entity">each</span> {|<span class="Variable">os</span>| <span class="Variable">self</span>.<span class="Entity">oses</span> <span class="Keyword">&lt;&lt;</span> os}
  <span class="Keyword">end</span>
<span class="Keyword">end</span>
</pre>
<p>So there&#8217;s a bit of magic!  The update_attributes and save methods will assign the os_list hash from the params to our accessor &#8220;os_list&#8221; property automatically and thus provide us convenient access to the hash data in our callback handler.  This is Rails at its best.  <a href="http://paulbarry.com/articles/2007/10/24/has_many-through-checkboxes">Paul Barry</a> gets the credit for being the first to put it together (at least for me).  </p>
<p>What this method does is first clear out all the currently associated Oses.  Then, if there are no selected Oses (in which case, items will be []), nothing happens with the loop, otherwise, each item is pushed onto the browser.oses list.  When I first started writing Ruby on Rails apps, I was a stickler for not hitting the database unnecessarily and I would write lots of conditionals to avoid doing so.  </p>
<p>However, the number of bugs I found in such logic eventually led me down the path of aggressively reducing lines of code in situations where it simply does not matter.  Here, we&#8217;re talking about, at most, about 10 operating systems defined in the app I&#8217;m writing and I am very infrequently going to be adding new browsers to the list (about as often as a major version comes out as a rule of thumb).  Is it really worth the extra code and the extra specs (you are writing test cases, aren&#8217;t you?) to gain so little?  Rails is smart.  It&#8217;ll issue a delete statement only if there are actually Oses in the list and it&#8217;ll only issue one DELETE statement, too!  Check this session history out (for PostgreSQL):</p>
<pre class="twilight">  SQL (0.000153)   BEGIN
  SQL (0.000337)   DELETE FROM <span class="String"><span class="String">&quot;</span>browsers_oses<span class="String">&quot;</span></span> WHERE browser_id = 14 AND os_id IN (8,9)
  SQL (0.009701)   COMMIT
  SQL (0.000131)   BEGIN
  SQL (0.000194)   INSERT INTO <span class="String"><span class="String">&quot;</span>browsers_oses<span class="String">&quot;</span></span> (<span class="String"><span class="String">&quot;</span>browser_id<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>updated_at<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>os_id<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>created_at<span class="String">&quot;</span></span>) VALUES (14, <span class="String"><span class="String">'</span>2008-10-24 19:33:43.107494<span class="String">'</span></span>, 8, <span class="String"><span class="String">'</span>2008-10-24 19:33:43.107494<span class="String">'</span></span>)
  SQL (0.000649)   COMMIT
  SQL (0.000094)   BEGIN
  SQL (0.000191)   INSERT INTO <span class="String"><span class="String">&quot;</span>browsers_oses<span class="String">&quot;</span></span> (<span class="String"><span class="String">&quot;</span>browser_id<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>updated_at<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>os_id<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>created_at<span class="String">&quot;</span></span>) VALUES (14, <span class="String"><span class="String">'</span>2008-10-24 19:34:01.088552<span class="String">'</span></span>, 9, <span class="String"><span class="String">'</span>2008-10-24 19:34:01.088552<span class="String">'</span></span>)
  SQL (0.000570)   COMMIT
  SQL (0.000086)   BEGIN
  SQL (0.000199)   INSERT INTO <span class="String"><span class="String">&quot;</span>browsers_oses<span class="String">&quot;</span></span> (<span class="String"><span class="String">&quot;</span>browser_id<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>updated_at<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>os_id<span class="String">&quot;</span></span>, <span class="String"><span class="String">&quot;</span>created_at<span class="String">&quot;</span></span>) VALUES (14, <span class="String"><span class="String">'</span>2008-10-23 20:24:59.809242<span class="String">'</span></span>, 2, <span class="String"><span class="String">'</span>2008-10-23 20:24:59.809242<span class="String">'</span></span>)
  SQL (0.000657)   COMMIT
  SQL (0.000076)   BEGIN
  SQL (0.000110)   COMMIT
Redirected to http://localhost:3000/browsers/14
Completed <span class="Keyword">in</span> 0.08188 (12 reqs/sec) <span class="Keyword">|</span> DB: 0.01585 (19%) <span class="Keyword">|</span> 302 Found [http://localhost/browsers/14]
</pre>
<p>Now, if you&#8217;ve got a situation where 100&#8217;s of users are performing a similar action and the small doses truly add up to something significant in your daily logs, then definitely optimize.  Just be cognizant of your use-case and profile your application for performance before getting fancy with the conditional updates, otherwise you&#8217;re in the trap of premature optimization and not getting something else done you might have wish you were!</p>
<p>Ok, having digressed a bit, lets get back on course.  So what does the Browser Controller now look like?  Well, the only thing I have to add is a call to &#8220;get_all_oses&#8221; just in case of a failure to save and the redirect back to the same page occurs.  So this is what we have:</p>
<pre class="twilight"><span class="Keyword">def</span> <span class="Entity">get_all_oses</span>
  <span class="Variable"><span class="Variable">@</span>oses</span> <span class="Keyword">=</span> <span class="Support">Os</span>.<span class="Entity">find</span>(<span class="Constant"><span class="Constant">:</span>all</span>, <span class="Constant"><span class="Constant">:</span>order</span> =&gt; <span class="String"><span class="String">'</span>vendor, version<span class="String">'</span></span>)
<span class="Keyword">end</span>  

<span class="Comment"><span class="Comment">#</span> POST /browsers</span>
<span class="Comment"><span class="Comment">#</span> POST /browsers.xml</span>
<span class="Keyword">def</span> <span class="Entity">create</span>
  <span class="Variable"><span class="Variable">@</span>browser</span> <span class="Keyword">=</span> <span class="Support">Browser</span>.<span class="Entity">new</span>(params[<span class="Constant"><span class="Constant">:</span>browser</span>])
  get_all_oses

  respond_to <span class="Keyword">do </span>|<span class="Variable">format</span>|
    <span class="Keyword">if</span> <span class="Variable"><span class="Variable">@</span>browser</span>.<span class="Entity">save</span>
      flash[<span class="Constant"><span class="Constant">:</span>notice</span>] <span class="Keyword">=</span> <span class="String"><span class="String">'</span>Browser was successfully created.<span class="String">'</span></span>
      format.<span class="Entity">html</span> { <span class="Entity">redirect_to</span>(<span class="Variable"><span class="Variable">@</span>browser</span>) }
      format.<span class="Entity">xml</span>  { render <span class="Constant"><span class="Constant">:</span>xml</span> =&gt; <span class="Variable"><span class="Variable">@</span>browser</span>, <span class="Constant"><span class="Constant">:</span>status</span> =&gt; <span class="Constant"><span class="Constant">:</span>created</span>, <span class="Constant"><span class="Constant">:</span>location</span> =&gt; <span class="Variable"><span class="Variable">@</span>browser</span> }
    <span class="Keyword">else</span>
      format.<span class="Entity">html</span> { render <span class="Constant"><span class="Constant">:</span>action</span> =&gt; <span class="String"><span class="String">&quot;</span>new<span class="String">&quot;</span></span> }
      format.<span class="Entity">xml</span>  { render <span class="Constant"><span class="Constant">:</span>xml</span> =&gt; <span class="Variable"><span class="Variable">@</span>browser</span>.<span class="Entity">errors</span>, <span class="Constant"><span class="Constant">:</span>status</span> =&gt; <span class="Constant"><span class="Constant">:</span>unprocessable_entity</span> }
    <span class="Keyword">end</span>
  <span class="Keyword">end</span>
<span class="Keyword">end</span>

<span class="Comment"><span class="Comment">#</span> PUT /browsers/1</span>
<span class="Comment"><span class="Comment">#</span> PUT /browsers/1.xml</span>
<span class="Keyword">def</span> <span class="Entity">update</span>
  params[<span class="Constant"><span class="Constant">:</span>oses</span>] <span class="Keyword">||=</span> {}
  <span class="Variable"><span class="Variable">@</span>browser</span> <span class="Keyword">=</span> <span class="Support">Browser</span>.<span class="Entity">find</span>(params[<span class="Constant"><span class="Constant">:</span>id</span>])
  get_all_oses

  respond_to <span class="Keyword">do </span>|<span class="Variable">format</span>|
    <span class="Keyword">if</span> <span class="Variable"><span class="Variable">@</span>browser</span>.<span class="Entity">update_attributes</span>(params[<span class="Constant"><span class="Constant">:</span>browser</span>])
      flash[<span class="Constant"><span class="Constant">:</span>notice</span>] <span class="Keyword">=</span> <span class="String"><span class="String">'</span>Browser was successfully updated.<span class="String">'</span></span>
      format.<span class="Entity">html</span> { <span class="Entity">redirect_to</span>(<span class="Variable"><span class="Variable">@</span>browser</span>) }
      format.<span class="Entity">xml</span>  { head <span class="Constant"><span class="Constant">:</span>ok</span> }
    <span class="Keyword">else</span>
      format.<span class="Entity">html</span> { render <span class="Constant"><span class="Constant">:</span>action</span> =&gt; <span class="String"><span class="String">&quot;</span>edit<span class="String">&quot;</span></span> }
      format.<span class="Entity">xml</span>  { render <span class="Constant"><span class="Constant">:</span>xml</span> =&gt; <span class="Variable"><span class="Variable">@</span>browser</span>.<span class="Entity">errors</span>, <span class="Constant"><span class="Constant">:</span>status</span> =&gt; <span class="Constant"><span class="Constant">:</span>unprocessable_entity</span> }
    <span class="Keyword">end</span>
  <span class="Keyword">end</span>
<span class="Keyword">end</span>
</pre>
<p>One last trick for the eagle eyes:  The form image I posted positions the labels in bold above the inputs and with a trailing colon, but nary a &lt;BR&gt; element (or colons) to be seen in the views.  I accomplished this with simple CSS styling by switching the label element to a block element (rather than inline as is the default) and then providing the colon as additional content:</p>
<pre class="twilight"><span class="CssTagName">label</span> {
	<span class="CssPropertyName">display</span>: <span class="CssPropertyValue">block</span>;
	<span class="CssPropertyName">font-weight</span>: <span class="CssPropertyValue">bold</span>;
}
<span class="CssTagName">label</span><span class="MetaTagInline"><span class="MetaTagInline">:</span>after</span> {
	<span class="CssPropertyName">content</span>: <span class="String"><span class="String">'</span>:<span class="String">'</span></span>;
}
</pre>
<p>So there you have it.  Leveraging the Rails framework appropriately, you can easily provide a checklist generated from one model on another&#8217;s edit form and have those records maintained in a many-to-many relationship without bloating your views or controllers.  </p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/rails-has-and-belongs-to-many-habtm-demystified/17/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
