<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>DogBiscuit</title>
    <description>... mmm, crunchy!</description>
    <link>http://dogbiscuit.org/mdub/weblog</link>
    <language>en-us</language>
    <generator>EvenYetAnotherWeblog</generator>
    <item>
      <title>ReadOnlyFormBuilder</title>
      <guid>http://dogbiscuit.org/mdub/weblog/Tech/Programming/Ruby/Rails/ReadOnlyFormBuilder</guid>
      <pubDate>Sat, 08 Mar 2008 22:00:00 +1100</pubDate>
      <description><![CDATA[<p>
For RubyOnRails developers, <a href='http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html'><tt>form_for</tt> and <tt>fields_for</tt></a>
are the accepted way of DRYing up form templates. You know the deal; you code
</p>
<pre>
&lt;% form_for :customer, :url =&gt; customers_path() do |customer_form| %&gt;
  &lt;p&gt;
    &lt;label&gt;Name:&lt;/label&gt; 
    &lt;%= customer_form.text_field :first_name, :size =&gt; 15 %&gt;
    &lt;%= customer_form.text_field :last_name, :size =&gt; 20 %&gt;
  &lt;/p&gt;
  ... etc ...
&lt;% end %&gt;
</pre>
<p>
and you get
</p>
<pre>
&lt;form action=&quot;/customers&quot; method=&quot;post&quot;&gt;
  &lt;p&gt;
    &lt;label&gt;Name:&lt;/label&gt; 
    &lt;input id=&quot;customer_first_name&quot; name=&quot;customer[first_name]&quot; size=&quot;15&quot; type=&quot;text&quot; /&gt;
    &lt;input id=&quot;customer_last_name&quot; name=&quot;customer[last_name]&quot; size=&quot;20&quot; type=&quot;text&quot; value=&quot;&quot; /&gt;
  &lt;/p&gt;
  ... etc ...
&lt;/form&gt;
</pre>
<p>
Rails generates sensible field names and ids for you, and slurps existing values out of the model object.  So far, so good.
</p>
<p>
Lately, I've taken to using the same trick when presenting data, not just when editing it.  So, whereas before I might have written:
</p>
<pre>
  &lt;p&gt;
    &lt;label&gt;Name:&lt;/label&gt; 
    &lt;span id=&quot;customer_first_name&quot;&gt;&lt;%= h @customer.first_name %&gt;&lt;/span&gt;
    &lt;span id=&quot;customer_last_name&quot;&gt;&lt;%= h @customer.last_name %&gt;&lt;/span&gt;
  &lt;/p&gt;
  ... etc ...
</pre>
<p>
I'll now code it up as:
</p>
<pre>
&lt;% fields_for :customer, :builder =&gt; ReadOnlyFormBuilder do |customer_form| %&gt;
  &lt;p&gt;
    &lt;label&gt;Name:&lt;/label&gt; 
    &lt;%= customer_form.text_field :first_name, :size =&gt; 15 %&gt;
    &lt;%= customer_form.text_field :last_name, :size =&gt; 20 %&gt;
  &lt;/p&gt;
  ... etc ...
&lt;% end %&gt;
</pre>
<p>
and get the same output.  (In case you're wondering, the ids are there to help with automated testing).
</p>
<p>
Note the similarity between the last code snippet and the first one on this page; apart from the first line they're
indentical. Usually, I'll put the field-declarations themselves in a partial that's shared between "new", "edit" and "show"
actions.  That way, your "show" page automatically gets identical layout to the others, just with raw values in place of editable fields.
</p>
<p>
The ReadOnlyFormBuilder class itself it fairly straightforward - I'm planning to wrap it up into a plugin sometime soon.  In the meantime, the implementation of text_field looks something like this:
</p>
<pre>
def text_field(attribute, options={})
  content_tag(&quot;span&quot;, html_escape(value_of(attribute)), :id =&gt; &quot;#{@object_name}_#{attribute}&quot;)
end

def value_of(attribute)
  value = model.send(attribute)
end

def model
  @object || @template.instance_variable_get(&quot;@#{@object_name}&quot;)
end
</pre>
]]></description>
    </item>
  </channel>
</rss>
