<?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; CSS</title>
	<atom:link href="http://ramblings.gibberishcode.net/archives/category/programming/css/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>Rails has and belongs to many (habtm) demystified</title>
		<link>http://ramblings.gibberishcode.net/archives/rails-has-and-belongs-to-many-habtm-demystified/17</link>
		<comments>http://ramblings.gibberishcode.net/archives/rails-has-and-belongs-to-many-habtm-demystified/17#comments</comments>
		<pubDate>Mon, 27 Oct 2008 14:49:02 +0000</pubDate>
		<dc:creator>Michael</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby Language]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[many-to-many]]></category>
		<category><![CDATA[rails]]></category>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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