<?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; Ruby Language</title>
	<atom:link href="http://ramblings.gibberishcode.net/archives/category/programming/ruby/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>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>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>
		<item>
		<title>Converting Oddmuse Wiki to Edgewall Trac</title>
		<link>http://ramblings.gibberishcode.net/archives/converting-oddmuse-wiki-to-edgewall-trac/13</link>
		<comments>http://ramblings.gibberishcode.net/archives/converting-oddmuse-wiki-to-edgewall-trac/13#comments</comments>
		<pubDate>Thu, 02 Oct 2008 16:30:38 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Macs]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python Language]]></category>
		<category><![CDATA[Ruby Language]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[oddmuse]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[trac]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=13</guid>
		<description><![CDATA[Our company began long ago with wiki&#8217;s, but we chose the Oddmuse wiki way back when.  These days, we&#8217;re heavy users of Trac wiki because of its integrated ticket support system.  So what to do with all those old wiki&#8217;s that folks have stopped using and reading.  The Oddmuse wikis still hold [...]]]></description>
			<content:encoded><![CDATA[<p>Our company began long ago with wiki&#8217;s, but we chose the Oddmuse wiki way back when.  These days, we&#8217;re heavy users of Trac wiki because of its integrated ticket support system.  So what to do with all those old wiki&#8217;s that folks have stopped using and reading.  The Oddmuse wikis still hold valuable data, but they have since become an administrative overhead to keep around, so I decided to convert them all to Edgewall&#8217;s Trac. </p>
<p>To get started, I needed to know how to get the data into Trac.  The following links gave me an API I could utilize to create trac pages and content:</p>
<p><a href="http://trac.edgewall.org/wiki/TracDev/DataModels">Trac Data Models</a><br />
<a href="http://trac.edgewall.org/browser/trunk/trac/wiki/model.py">The Data model Python code</a></p>
<p>Great!  Except there&#8217;s one small problem.  I don&#8217;t really know python all that well, even though I did do a bit of Zope development, oh, five years ago.  These days, my language of choice is Ruby, so I needed to figure out how to parse the Oddmuse syntax and turn it into Trac syntax.  The strategy:  Parse with Ruby, load cleaned page files with Python.  </p>
<p>This script will take a filename at command line and convert it and save back to file, but different extension (I chose *.om for &#8220;oddmuse&#8221;).  In the script below, I made the command-line optional as I discovered I didn&#8217;t handle every case as I worked on developing this script, so I simply changed the line that pulls the command-line argument to point to a specific file and output such to terminal and this allowed me to debug and fix as I went:</p>
<pre  name="code" class="ruby:nocontrols">
#!/opt/local/bin/ruby
# $FS  = "\xb3";      # The FS character is the RECORD SEPARATOR control char in ASCII
# $FS0 = "\xb3";      # The old FS character is a superscript "3" in Latin-1
# $FS1 = $FS . '1';   # The FS values are used to separate fields
# $FS2 = $FS . '2';   # in stored hashtables and other data structures.
# $FS3 = $FS . '3';   # The FS character is not allowed in user data.

FS = 179.chr

SITE_NAME = "corporate_wiki"
ATTACHMENT_URL_BASE = "https://intranet.example.com/#{SITE_NAME}/attachment/wiki/ConvertedAttachments/"

require 'find'
require 'ftools'

def safe_page_name(pagename)
  result = pagename.gsub("'","")
  result = result.slice(/(\w+)/).first
end

def get_section(page, section)
  page.each_with_index {|e,i| return page[i+1] if e == section}
  return ''
end

def asterick_prefixed(text)
  t = text.match(/(\*+)([^\b]*)/)
  return text if t.nil?

  tokens = t.to_a
  return ('  ' * tokens[1].size) + '* ' + tokens[2]
end

def colon_prefixed(text)
  return "  #{colon_prefixed(text.slice(1,text.size))}" if text[0] == ":"[0]
  return text
end

def pound_prefixed(text)
  return "  1. #{text.slice(1,text.size)}" if text[0] == "#"[0]
  return text
end

def fix_headers(text)
  t = text.match(/(=+)([^=]+)(=+)/)
  return text if t.nil?

  tokens = t.to_a
  return "#{tokens[1]} #{tokens[2].strip} #{tokens[1]}"
end

def replace_a_url(url, text)
  text.gsub!("http://#{url}", ATTACHMENT_URL_BASE)
  text.gsub!("https://#{url}", ATTACHMENT_URL_BASE)
  text.gsub!("http:/#{url}", ATTACHMENT_URL_BASE)
  text.gsub!("https:/#{url}", ATTACHMENT_URL_BASE)
  return text
end

def replace_wiki_urls(text)
  matches = text.match(/\[http(.)*\]/)
  result = text
  if matches
    result = replace_a_url("wiki.example.com/#{SITE_NAME}/wikifiles/", result)
    result = replace_a_url("pdfreviewfiles/", result)
    result = replace_a_url("cgi-bin/", result)
  end
  result
end

def convert_formats(text)
  result = text.gsub(/\[\[(\w+)\]\]/,"[wiki:" + '\1' + "]")
  result = asterick_prefixed(result)
  result = colon_prefixed(result)
  result = pound_prefixed(result)
  result = replace_wiki_urls(result)
  result = fix_headers(result)
  result
end

def oddmuse_to_trac(text)
  result = ''
  in_pre = false
  text.split("\n").each do |line|

    # Detect indented lines as these are rendered as PRE html blocks
    trimmed = line.lstrip
    is_prefixed = ((trimmed.size < line.size) and (trimmed[0] != '*'[0]))
    result << "{{{\n" if (is_prefixed and !in_pre)

    result << "}}}\n" if (!is_prefixed and in_pre)
    in_pre = is_prefixed

    # Don't process special characters when in PRE block
    if in_pre
      result << line << "\n"
    else
      result << convert_formats(line) << "\n"
    end
  end
  result += "}}}\n" if in_pre
  result
end

path = ARGV[0] || "page/U/UsingThePhones.db"
raw_page = File.new(path).read
page2 = raw_page.split(FS + '2')
page3 = raw_page.split(FS + '3')

text = get_section(page3, 'text')

pagename = File.basename(path).split('.').first
author = get_section(page2, 'username')
address = get_section(page2, 'ip')
body = oddmuse_to_trac(text)

puts "writing: #{pagename}.om"
outfile = File.new(path.gsub('.db','.om'),'w')
outfile.puts 'pagename:' + pagename
outfile.puts 'author:' + author
outfile.puts 'address:' + address
outfile.puts body
outfile.close

puts body if ARGV[0].nil?
</pre>
<p>Below, comes the Python side of the equation.  Once I did the heavy lifting in Ruby, I needed to generate all the pages.  As you can see, there's some parsing happening, but its very simple parsing and I was able to apply what simple Python knowledge I still retained pretty effectively:</p>
<pre  name="code" class="python:nocontrols">
import sys
from trac.env import Environment
from trac.wiki.model import WikiPage

print sys.argv[1]
file = open(sys.argv[1], 'r')
pagename = file.readline().split(':')[1].split('\n')[0]
author_name = file.readline().split(':')[1].split('\n')[0]
address = file.readline().split(':')[1].split('\n')[0]

text = file.read()

env = Environment('/srv/www/trac/corporate_wiki')

# Read an existing or new WikiPage:
page = WikiPage(env, pagename)
if page.text != text:
        page.text = text
        page.save(author=author_name, comment='imported from oddmuse wiki', remote_addr=address)
</pre>
<p>As you can see, this file simply takes the command line argument, open the file for reading, pull the various variables out with the remainder of the file going to the page content.</p>
<p>During the conversion, I noticed some pages were failing to convert at all, like "Michael'sTodoList"  The culprit, the tick in the page name and thus the filename.  The scripts themselves weren't the problem, it was the xargs parameter passing that was the issue (getting to that below).  So I ran the below script to rename all the troublesome filenames and then added similar tick to underscore substitution in the main Ruby script above.  </p>
<pre  name="code" class="ruby:nocontrols">
require 'find'
require 'ftools'

total_size = 0

Find.find('./page') do |path|
  if FileTest.directory?(path)
    if File.basename(path)[0] == ?.
      Find.prune       # Don't look any further into this directory.
    else
      next
    end
  else
    if path.match(/[\']/)
      safe_path = path.gsub("'", "_")
      puts path + ' to ' + safe_path
      File.move(path, safe_path)
    end
    end
  end
</pre>
<p>A simple up-front execution of the script was all that was needed to now be able to pick up the missing pages:</p>
<pre  name="code" class="ruby:nocontrols">
ruby fix_unsafe_files.rb
</pre>
<p>Finally, to bring it all together, I utilized find to locate all the *.db Oddmuse files which I had located into the various wiki subfolders where these scripts sat, passing the filename to the script via the xargs utility:</p>
<pre  name="code" class="ruby:nocontrols">
find . -name *.db -print0 | xargs -0 -L 1 ruby rdpage.rb
</pre>
<p>I then essentially repeated the above, but for the generated *.om files, passing to the Python mkpage.py script:</p>
<pre  name="code" class="ruby:nocontrols">
find . -name *.om -print0 | xargs -0 -L 1 python mkpage.py
</pre>
<p>One last thing, before we're done.  Each wiki had attachments.  So I had to think how to get those attachments referenced and linked to the Trac wiki.  A little investigation revealed that each attachment got a database entry in the attachment table.  My task was a bit complicated by the fact that the users over the years in the Oddmuse environment scattered their attachments everywhere and also used varying syntax to refer to them, hence, if you review the main Ruby parsing script, you'll see the "replace_a_url" method above that cleans all those funky URLs up.  So the script I used below simply scans through all the directories where we had files stored and attached them to one "ConvertedAttachments" page.  Probably not the ideal solution, but again, got the job done quickly.</p>
<pre  name="code" class="ruby:nocontrols">
#  type |          id          |  filename  |  size  |    time    | description | author |      ipnr
# ------+----------------------+------------+--------+------------+-------------+--------+----------------
#  wiki | ConvertedAttachments | gotapi.png | 200272 | 1218381947 |             | michael | 192.168.16.100

path = ARGV[0] || 'generate_attachments.rb'
filename = File.basename(path)

puts "insert into attachment values ('wiki', 'ConvertedAttachments', '#{filename}', #{FileTest.size(path)}, null, null, 'oddmuse','192.168.1.246');"
</pre>
<p>So, running the above needs to be piped to a SQL fisle and then executed against your Trac database.  In my case, Postgresql.  Since I had many directories to snatch up, I ran it for each folder as appropriate and simply kept appending until I had all the attachment directories represented.</p>
<pre  name="code" class="ruby:nocontrols">
ls | xargs -0 -L 1 >> attachments.sql
psql trac_db < attachments.sql
</pre>
<p>All in all, not too bad of a conversion for a few hour's work.  Its about 95% correct.  Some of the page names didn't translate to Trac, and could probably do with some regexp search and replace on the page names themselves.  The biggest gain is that we have preserved the information in the old systems by porting it to the new systems we all know and use on a daily basis, so WikiGardening is more likely to keep the content fresher and its one less system for our end-users to figure out how to use.  </p>
<p>I can now retire the server running Oddmuse, stop doing backups and keeping up with documentation and training new system administrators on how to manage Oddmuse AND Trac.  </p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/converting-oddmuse-wiki-to-edgewall-trac/13/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Geocoded Zipcodes</title>
		<link>http://ramblings.gibberishcode.net/archives/geocoded-zipcodes/11</link>
		<comments>http://ramblings.gibberishcode.net/archives/geocoded-zipcodes/11#comments</comments>
		<pubDate>Mon, 07 Jul 2008 23:20:26 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[Ruby Language]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[loading data]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[zip codes]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=11</guid>
		<description><![CDATA[You would think that loading up a database of zip codes would be an extremely simple case of finding a public database on www.usps.gov, and then loading up with a database bulk load.  It turns out that, while the USPS does offer products for you to purchase, and a rather nice lookup interface for [...]]]></description>
			<content:encoded><![CDATA[<p>You would think that loading up a database of zip codes would be an extremely simple case of finding a public database on www.usps.gov, and then loading up with a database bulk load.  It turns out that, while the USPS does offer products for you to purchase, and a rather nice lookup interface for looking up zip codes and so on, there&#8217;s not really any free data to be had that I could tell.  So the hunt was on to find some zip code data, preferably geocoded (latitude/longitude for GIS) zip codes and then load them into MySQL.</p>
<p>A bit of hunting around turned up <a href="">this list of zip code databases</a>.  The first link to CivicSpace database appears to be defunct (I got a Go Daddy &#8220;this page is parked&#8221; page).  So, the next free one, offered by <a href="http://www.populardata.com/index.html">Popular Data</a> turned out to be exactly what I was looking for.  It may be a &#8220;little old&#8221; as the review site says, but its good enough for me to get started with associating my data with geocoded locations and explore the wonderful world of mapping offered by Google&#8217;s Maps API.  </p>
<p>To load it up in MySQL and PostgreSQL, I used the following Ruby script to generate a bunch of insert statements:</p>
<pre  name="code" class="ruby:nocontrols">
require 'rubygems'
require 'fastercsv'
source_file = 'ZIP_CODES.txt'
outfile = File.new('us_zip_codes.sql','w')

# generate the truncate statement if we want to empty the table
outfile.puts "truncate us_zip_codes;"

# generate the SQL Insert statements
FasterCSV.foreach(source_file, :headers => false) do |cols|
  row = "INSERT INTO us_zip_codes VALUES ("
  row << as_string(cols[0]) << ","
  row << as_number(cols[1]) << ","
  row << as_number(cols[2]) << ","
  row << as_string(cols[3]) << ","
  row << as_string(cols[4]) << ","
  row << as_string(cols[5]) << ","
  row << as_string(cols[6]) << ");"
  outfile.puts row
end
outfile.close
puts "copied #{i} records."
</pre>
<p>Create the zip code table with the following SQL:</p>
<pre  name="code" class="sql:nocontrols">
create table us_zip_codes (
  zip_code char(5),
  latitude float(10,6),
  longitude float(10,6),
  city varchar(255),
  state char(2),
  county varchar(255),
  zip_class varchar(255)
);
</pre>
<p>And finally, with the table in place and the SQL insert statements generated, I loaded the data into MySQL with the following from command line:</p>
<pre  name="code" class="ruby:nocontrols">
mysql target_db_name < us_zip_codes.sql
</pre>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/geocoded-zipcodes/11/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>DRYing your Views</title>
		<link>http://ramblings.gibberishcode.net/archives/drying-your-views/8</link>
		<comments>http://ramblings.gibberishcode.net/archives/drying-your-views/8#comments</comments>
		<pubDate>Sat, 05 Jul 2008 20:48:27 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Ruby Language]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[dry]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby block]]></category>
		<category><![CDATA[views]]></category>

		<guid isPermaLink="false">http://ramblings.gibberishcode.net/?p=8</guid>
		<description><![CDATA[Let me start out by saying that I am finally beginning to understand a bit about that magical Ruby block notion and how implementing methods through block passing can really empower you as a Ruby developer.  Thanks to, a most excellent Ruby tutorial, I am definitely feeling a good bit more empowered about getting [...]]]></description>
			<content:encoded><![CDATA[<p>Let me start out by saying that I am finally beginning to understand a bit about that magical Ruby block notion and how implementing methods through block passing can really empower you as a Ruby developer.  Thanks to, a most excellent <a href="http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_containers.html">Ruby tutorial</a>, I am definitely feeling a good bit more empowered about getting my Views in Rails all DRY&#8217;d up.</p>
<p>The problem:  I wanted to introduce a property editor metaphor for the website I&#8217;m working on where properties could expose edit forms for just about any situation, much like wordpress&#8217; widget interface does.  </p>
<p>That is, there&#8217;s an area of the current page that shows basic information about the property in a read-only (and preferably compact) form, and user could click an &#8220;edit&#8221; button and exposed an editable version of the properties.  The &#8220;edit&#8221; link becomes a &#8220;cancel&#8221; link, which, when clicked, simply discards the edit form and return the initial compact view state.</p>
<p><a href='http://ramblings.gibberishcode.net/wp-content/uploads/2008/07/click_edit_to_show.png'><img src="http://ramblings.gibberishcode.net/wp-content/uploads/2008/07/click_edit_to_show.png" alt="Clicking EDIT to extend the display for editing" title="click_edit_to_show" width="280" height="206" class="alignleft size-full wp-image-10" /></a></p>
<p>The problem is, Rails doesn&#8217;t really have any good helpers for reusing a design concept in your views.  I found that even with partials, the code was really starting to bog down and become both unmaintainable and unreadable.  I needed a simple mechanism to construct my property editors.  I started out with helper methods.  But that wasn&#8217;t much better as the code just started ending as ruby here-docs and became a maintenance issue of another sort!  Take a look at this embarrassment:</p>
<pre name="code" class="ruby:nocontrols">
result = "&lt;table&gt;&lt;tr&gt;"
result += "&lt;th colspan=2&gt;"
result += button_image_action('Group selected together', 'link.png')
result += button_image_action('Copy selected to this group', 'link_add.png')
result += button_image_action('Move selected to this group', 'link_go.png')
result += button_image_action('copy group', 'page_copy.png')
result += button_image_action('cut group', 'cut.png')
result += button_image_action('paste group', 'page_paste.png')
result += button_image_action('delete group', 'delete.png')
result += "&lt;/th&gt;&lt;/tr&gt;"
result += "&lt;/table&gt;"
</pre>
<p>Ok, I admit it, I chopped out more than half again as many lines as you&#8217;re looking at there, and perhaps worse, this isn&#8217;t actually the original HTML code that led me down this path, but lets take a look at this approach anyway, as I learned something valuable in the process and it <em>was</em> my first attempt at DRYing my views. First thing, first, get the above HTML back into the erb file:</p>
<pre name="code" class="ruby:nocontrols">
<table>
<th colspan=2>
			<%= button_image_action('Group selected together', 'link.png') %>
			<%= button_image_action('Copy selected to this group', 'link_add.png') %>
			<%= button_image_action('Move selected to this group', 'link_go.png') %>
			<%= button_image_action('copy group', 'page_copy.png') %>
			<%= button_image_action('cut group', 'cut.png') %>
			<%= button_image_action('paste group', 'page_paste.png') %>
			<%= button_image_action('delete group', 'delete.png') %>
		</th>
</tr>
</table>
</pre>
<p>Which promptly let me to trying something like this:</p>
<pre name="code" class="ruby:nocontrols">
def button_image_action(title, image_filename, button_text = '', url = '')
    form_for @cube url do |f|
  	  <<-TEXT
  	    <BUTTON alt='#{title}' title='#{title}' type='submit'>#{button_text}
  	    <IMG alt='#{title}' title='#{title}' src='/images/#{image_filename}'>
  	    </BUTTON>
  	  TEXT
     end
  end
</pre>
<p>I thought it was shaping up nicely, but I got completely blindsided when it came to rendering this bit.  You see, the Rails Form Helpers are unavailable in a regular helper!  They require ERB (being inside <% %> and <%= %>) to actually properly render their blocks.</p>
<p>I fiddled around for a bit to try to jump this hurdle, but it just simply ain&#8217;t gonna work without some serious hacking. I&#8217;m happy to report that I got a little wiser and stepped back from the problem and reevaluated my approach in general.  I realized, I wasn&#8217;t getting away from doing HTML code in helpers!  Bottom line:  Helpers are great, but you&#8217;re doing something clearly against &#8220;The Rails Way&#8221; when you start rendering large chunks of HTML code from helpers.  It just isn&#8217;t a great approach and if you have designers on your team, they can get quite lost hunting around for all those HTML snippets. </p>
<p>So, how could I get <em>all</em> of my HTML back into *.erb files where they belonged, yet develop some helpers that would make mincemeat of the coding effort to build these fancy toolbars and forms I had coming?  Fellow colleague, Steven Beales said, &#8220;you need to use Ruby blocks.&#8221;  To which, my first reaction was, &#8220;what are Ruby blocks?&#8221;  To my great benefit, he explained by pointing me straight at <a href="http://www.igvita.com/2007/03/15/block-helpers-and-dry-views-in-rails/ ">Block Helpers and DRY Views in Rails</a>.</p>
<p>Truth be told, I mostly understood this article, but not entirely.  Even so, I dutifully set off to solve my problem with this approach.  This led me to a bit of copying and pasting (and crediting)&#8230;</p>
<pre name="code" class="ruby:nocontrols">
  # From:  http://errtheblog.com/posts/11-block-to-partial
  #
  # captures the output of our passed block using Rails’ capture method and adds
  # it to our options hash under the key of :body. Next it renders our passed
  # partial, sending in our options hash as :locals
  def block_to_partial(partial_name, options = {}, &#038;block)
    options.merge!(:body => capture(&#038;block))
    concat(render(:partial => partial_name, :locals => options), block.binding)
  end
</pre>
<p>Look at that carefully and, if I may be so bold to suggest, go read up on <a href="http://errtheblog.com/posts/11-block-to-partial">ERR the Blog</a> to better understand as this method is key and I daresay was appropriately called &#8220;tomfoolery&#8221; by the wise authors therein.  This bit of code really forced me to finally begin to learn and understand what the heck block passing was all about.  In a nutshell, this little gem lets you pass options that become local variables to the partial and the block is the contents to be rendered within the partial when you <em>yield</em> to the passed block.</p>
<div class="aside">
<h2> An Aside </h2>
<p>There were a couple instances where I was building a repeated elements with pretty much the same resulting HTML (namely toolbar buttons where only the image, caption, alt, title, and onclick events were changing).  Taking inspiration from <a href="http://www.igvita.com/2007/03/15/block-helpers-and-dry-views-in-rails/">Ilya Grigorik&#8217;s rounded box implementation</a>, I felt he had the approach I wanted, but I didn&#8217;t always need to pass in blocks for what I was do in every situation.  Unfortunately, I didn&#8217;t understand blocks!  I had to go back to school and understand them in order to adapt his approach to my situation.  After schooling myself a bit, I came up with this modified version of the block_to_partials to pass those attributes in (no block necessary!).  I named the simplified version &#8220;variables_to_partial&#8221; as follows:</p>
<pre name="code" class="ruby:nocontrols">
  # Calls given partial, injecting the options hash into the partial's local hash
  def variables_to_partial(partial_name, options = {})
    render(:partial => partial_name, :locals => options)
  end
</pre>
</div>
<p>The block_to_partial is a great start, but I wanted to simplify my calls and also enforce a bit of use-pattern on the developer (i.e. me) so that all property editors had essentially the same behavior pattern (and components).  Thus, we introduce the property editor container which in turn can have one or more sections associated with it:</p>
<pre name="code" class="ruby:nocontrols">
  # Generates a division around the given block that is styled with "property-editor"
  # Property editors are intended as a view on data that has both a condensed display and
  # an expanded display that lets you edit the information contained in the property editor.
  def property_editor(id, title, options = {}, &#038;block)
    @id = id
    block_to_partial 'layouts/property_editor', options.merge(:id => id, :title => title), &#038;block
  end
</pre>
<pre name="code" class="ruby:nocontrols">
  # Renders content of a section (provided by block) inside a property editor division
  # The stylesheet contains styling for the following section_id's:
  #   => "show" - the section initially visible
  #   => "edit" - the section made visible when the edit button is clicked
  def property_editor_section(section_id, options = {}, &#038;block)
    block_to_partial('layouts/property_editor_section',
      options.merge(:section_class => "property-editor-#{section_id}",
        :section_id => "#{@id}-#{section_id}"),
        &#038;block)
  end
</pre>
<p>The property editor partial:</p>
<pre name="code" class="ruby:nocontrols">
&lt;div &lt;%= %[id="#{id}"] %&gt; class="property-editor"&gt;
	&lt;div class="property-editor-title"&gt;
		&lt;div style="float:right"&gt;
			&lt;a href="javascript: void(0)" onclick="toggle_div('&lt;%= id %&gt;-show');toggle_div('&lt;%= id %&gt;-edit');"&gt;edit&lt;/a&gt;
		&lt;/div&gt;
  		&lt;%= title %&gt;
	&lt;/div&gt;
	&lt;%= body %&gt;
&lt;/div&gt;
</pre>
<p>and the property editor sections are rendered with this partial:</p>
<pre name="code" class="ruby:nocontrols">
&lt;div &lt;%= %[id="#{section_id}"] %&gt; &lt;%= %[class="#{section_class}"] %&gt; &lt;%= %[style="display:none"] if section_id =~ /(.+)?\-edit/  %&gt;&gt;
	&lt;%= body %&gt;
&lt;/div&gt;
</pre>
<p>With these helpers and partials, property editors as a concept is very easy to pull together in my view files.  As you can see, if my section is an &#8220;edit&#8221; section, its hidden at the outset.  The button to toggle between show and edit is in the property editor partial itself in which an onclick javascript calls toggle_div to make this happen.  The Javascript is very straightforward:</p>
<pre name="code" class="javascript:nocontrols">
function toggle_div(div_name) {
	var div = $(div_name);
	div.getStyle('display') == 'none' ? div.setStyle('display', 'block') :	div.setStyle('display', 'none');
}
</pre>
<p>Here&#8217;s just one such property editor operating on my &#8220;cube model&#8221;:</p>
<pre name="code" class="ruby:nocontrols">
&lt;% property_editor 'properties', 'Properties' do %&gt;
	&lt;% property_editor_section 'show' do %&gt;
		&lt;%= @cube.name %&gt;&lt;br/&gt;
		&lt;%= render :partial =&gt; '/cubes/cube_stats' %&gt;
	&lt;% end %&gt;

	&lt;% property_editor_section 'edit' do %&gt;
		&lt;%= render :partial =&gt; 'form' %&gt;
	&lt;% end %&gt;
&lt;% end %&gt;
</pre>
<p>What&#8217;s more, I had a complete set of CSS selectors with which I could control my property editor and its associated sections:  </p>
<pre name="code" class="css:nocontrols">
.property-editor {
	margin-top: 5px;
	border: 3px solid #FDEFE6;
}

.property-editor-title {
	padding: 2px;
	padding-left: 5px;
	padding-right: 5px;
	background-color: #EEE;
	color: #2F6569;
}

.property-editor-show, .property-editor-edit {
	padding: 5px;
}

.property-editor p {
	margin: 0px;
	padding: 0px;
}
</pre>
<p>Well, all in all, that&#8217;s a good bit of rambling, but I hope others can benefit from my experiences with Ruby, blocks, partials, and DRY up those views.</p>
]]></content:encoded>
			<wfw:commentRss>http://ramblings.gibberishcode.net/archives/drying-your-views/8/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
