<?xml version="1.0"?>
<rss version="2.0">
  <channel>
    <title>Jim Clark - Blogs at Near Infinity</title>
    <link>http://www.nearinfinity.com/blogs/jim_clark</link>
    <description>Jim Clark's Blogs</description>
    <language>en-us</language>
    <copyright>Copyright 2013</copyright>
    <lastBuildDate>Tue, 21 May 2013 03:00:20 -0400</lastBuildDate>
    <docs>http://www.rssboard.org/rss-specification</docs>
    
      <item>
        <title>ActiveRecord: Nested Attributes </title>
        <link>http://www.nearinfinity.com/blogs/jim_clark/activerecord_nested_attributes.html</link>
        <guid>http://www.nearinfinity.com/blogs/jim_clark/activerecord_nested_attributes.html</guid>
        <pubDate>Mon, 02 May 2011 23:25:38 -0400</pubDate>
        
        <author>Jim Clark</author>
        
        <description>&lt;p&gt;My project recently started developing a web app using Rails 3 and Extjs, a pure JavaScript frontend, i.e. no ERB, haml, etc.  We have several multi-page forms where we use a JavaScript model to hold the form data and upon save serialize the JSON back to the server. If successful, the updated data is rendered as JSON and sent back to the client.  
&lt;/p&gt;
&lt;p&gt;
The model has a simple one-to-many relationship (parent/children)
&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Jim&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; 
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Larry&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:&amp;#39;Curly&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Moe&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Parent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;attr_accessible&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;has_many&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:children&lt;/span&gt; 
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Child&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;belongs_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:parent&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
My expectation was that when I save the parent data, via update_attributes, both the parent and child data save together in a single transaction. 
&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ParentsController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ApplicationController&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Parent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update_attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
Being new to developing Rails apps in the &quot;real world&quot; I had not dealt with this, what I thought to be, common scenario.  I found that out of the box the parent data saves, but not the child data.  I first explored the book &quot;Agile Web Development with Rails&quot;, but didn't find what I needed.  Next I checked out the Rails Guides, in particular the section on &lt;a href=&quot;http://guides.rubyonrails.org/association_basics.html#options-for-has_many&quot;&gt;associations&lt;/a&gt; The first setting I found was the :autosave setting:
&lt;/p&gt;

&lt;blockquote&gt;&lt;em&gt;
If you set the :autosave option to true, Rails will save any loaded members and destroy members that are marked for 
destruction whenever you save the parent object.
&lt;/em&gt;&lt;/blockquote&gt;

&lt;p&gt;
Seemed like a good fit.
&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;has_many&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:autosave&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
However, the children still did not save when calling update_attributes (I'm still not sure exactly what this is used for)
&lt;/p&gt;

&lt;p&gt;
Next stop, Google. Some searching brought me to the ActiveRecord &quot;accepts_nested_attributes_for&quot; method. It turns out this is exactly what I needed.  So I added &quot;accepts_nested_attributes_for :children&quot; to Parent
&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Parent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;attr_accessible&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;has_many&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:children&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;accepts_nested_attributes_for&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:children&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
However, just adding &quot;accepts_nested_attributes_for :children&quot; wasn't enough.  It turns out that with the accepts_nested_attributes_for method, the Parent class receives a method called &quot;children_attributes=(attributes)&quot;.  This allows for the parent's children attributes to be updated.  This also means I have to update my JSON so that the &quot;children&quot; property is called &quot;children_attributes&quot;.  
&lt;/p&gt;


&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Jim&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;children_attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; 
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Larry&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:&amp;#39;Curly&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Moe&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Since I am using &quot;attr_accessible&quot; I also have to include &quot;children_attributes&quot; in the list
&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Parent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;attr_accessible&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:children_attributes&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;has_many&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:children&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;accepts_nested_attributes_for&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:children&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
Now calling &quot;parent.update_attributes&quot; saves both the parent and its children, within a single transaction.  Rails will handle inserts/updates/deletes appropriately.  If the child has an id, the child is updated.  If the child is missing an id, a new child is added.  If the child has the &quot;_destroy&quot; attribute set, the child is removed.
&lt;/p&gt;

&lt;p&gt;
The last todo was to serialize the JSON back to the client upon success. When trying this:
&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:include&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;my JSON included &quot;children&quot;, not &quot;children_attributes&quot;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Jim&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; 
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Larry&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:&amp;#39;Curly&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Moe&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;For the save to work correctly, the JSON needs &quot;children_attributes&quot;, (which is a bit of a disconnect between relationship and nested attribute naming conventions) I was not able to figure out how to get Rails and &quot;to_json&quot; to use &quot;children_attributes&quot;.  For my solution I did not &quot;:include =&amp;gt; :children&quot; in my call to &quot;to_json&quot; and I overrode &quot;as_json&quot;.  In my &quot;as_json&quot; I manually add the &quot;children attributes&quot; to the parent JSON.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;as_json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:children_attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]=[]&lt;/span&gt;
    
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:children_attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt; 
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Looking back on getting the save to work, it seems rather simple.  However, several things made this a little harder than it should have been.  The first being the documented coverage.  Surprisingly, this was not covered in the book &quot;AWDR&quot; or Rails Guides. It is spelled out quite well in the API docs, however, but you need to know about the NestedAttributes module  The &quot;:autosave&quot; setting misled me a bit.  I will need to go back and do a bit more research on this.  Lastly, the naming convention for nested attributes threw me off and the fact that I had to &quot;rig&quot; as_json. Perhaps there is a way to handle this by &quot;convention&quot;.&lt;/p&gt; 

&lt;p&gt;
For further reading check out &lt;a href=&quot;http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes&quot;&gt;Ryan's blog&lt;/a&gt; or &lt;a href=&quot;http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html&quot;&gt;the Nested Attributes API docs.&lt;/a&gt; 
&lt;/p&gt;
 
</description>
        
          <category term="ruby" label="ruby"/>
        
      </item>
    
      <item>
        <title>Introduction to PDF::TechBook</title>
        <link>http://www.nearinfinity.com/blogs/jim_clark/introduction_to_pdf_techbook.html</link>
        <guid>http://www.nearinfinity.com/blogs/jim_clark/introduction_to_pdf_techbook.html</guid>
        <pubDate>Mon, 30 Apr 2007 22:44:39 -0400</pubDate>
        
        <author>Jim Clark</author>
        
        <description>&lt;p&gt;
Recently I had an interest in producing PDF documents using Ruby on Rails.&amp;nbsp;
A quick Google search brought me to a Ruby PDF library called
&lt;a href=&quot;http://ruby-pdf.rubyforge.org/pdf-writer/&quot; title=&quot;PDF::Writer for Ruby&quot;&gt;PDF::Writer
for Ruby&lt;/a&gt; written by
&lt;a href=&quot;http://www.halostatue.ca/&quot; title=&quot;Austin Ziegler&quot;&gt;Austin
Ziegler&lt;/a&gt;.&amp;nbsp; As far as I can tell from the online manual PDF::Writer is a
fairly robust library.&amp;nbsp; The manual was well written and
generated by PDF::Writer itself, very impressive.&amp;nbsp; By reading Austin's
introductory
&lt;a href=&quot;http://www.artima.com/rubycs/articles/pdf_writer.html&quot; title=&quot;Artima article&quot;&gt;PDF::Writer
article&lt;/a&gt; I was able to get up and running quickly.&amp;nbsp; The article
demonstrates creating text, tables, drawings and inserting images.&amp;nbsp;
However, I didn't need to do anything fancy like create charts or drawings (see
the PACMAN example). &amp;nbsp; All I wanted was some basic header, text and code
styling.&amp;nbsp; Out of the box PDF::Writer allows you to do these sort of things
but it requires some additional work on your part.&amp;nbsp; PDF::Writer gives you
the primitives to work with to create whatever you want, but I didn't have the
time to go through the effort to create my own styling from scratch.&amp;nbsp;
Fortunately, Austin extended PDF::Writer to create PDF::TechBook.&amp;nbsp;
TechBook gives you the ability to mark up and style your content that can then
be used to generate a PDF document.&amp;nbsp; This is a brief introduction to
TechBook.
&lt;/p&gt;

&lt;p&gt;
The TechBook class extends PDF::Writer and is an interpreter that interprets a lightweight markup language.&amp;nbsp; You
feed the TechBook class a string or a file that contains content and TechBook
markup to generate a PDF document.&amp;nbsp; TechBook markup provides styling for
basic headings, preformatted blocks, code sections, columns, table of contents,
bulleted lists and a few other items.&amp;nbsp; I equate this to
something like an HTML-lite or textile for PDFs.&amp;nbsp; The markup
uses directives to indicate the start and end of a block of text.&amp;nbsp; Some
directives are line oriented like headers that only require a start
directive.&amp;nbsp; Other directives can span multiple lines like bulleted
lists.&amp;nbsp; We'll start with a basic example.&amp;nbsp;
&lt;/p&gt;

&lt;p&gt;
Headers, similar to the &amp;lt;H1-5&amp;gt; tags in HTML, are supported up to five
headers by using the somewhat awkward format &lt;code&gt;#&amp;lt;heading-text&amp;gt;&lt;/code&gt;, e.g.
&lt;/p&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;    1&amp;amp;lt;Level 1&amp;amp;gt;
    2&amp;amp;lt;Level 2&amp;amp;gt;
    3&amp;amp;lt;Level 3&amp;amp;gt;
    4&amp;amp;lt;Level 4&amp;amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

produces...&lt;br /&gt;&lt;br /&gt;
&lt;form mt:asset-id=&quot;217&quot; class=&quot;mt-enclosure mt-enclosure-image&quot; style=&quot;display: inline;&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/blogs/jim_clark/assets/headings.JPG&quot; alt=&quot;headings.JPG&quot; class=&quot;mt-image-none&quot; style=&quot;&quot; height=&quot;112&quot; width=&quot;692&quot; /&gt;&lt;/form&gt;&lt;br /&gt;&lt;br /&gt;

With TechBook you can create bulleted lists using &quot;discs&quot; or standard bullets.&amp;nbsp;
Here's an example showing how to create a bulleted list using the disc bullets.&amp;nbsp; (To create standard bullets replace &quot;disc&quot; with &quot;bullet&quot;)
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;    .blist disc
    Line item 1 with disc
    .endblist
    .blist disc
    Line item 2 with disc
    .endblist
    .blist disc
    Line item 3 with disc
    .endblist
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

produces...&lt;br /&gt;&lt;br /&gt;
&lt;form mt:asset-id=&quot;218&quot; class=&quot;mt-enclosure mt-enclosure-image&quot; style=&quot;display: inline;&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/blogs/jim_clark/assets/disc.JPG&quot; alt=&quot;disc.JPG&quot; class=&quot;mt-image-none&quot; style=&quot;&quot; height=&quot;71&quot; width=&quot;190&quot; /&gt;&lt;/form&gt;


&lt;p&gt;
In addition to headings and lists, TechBook allows you to preformat text and identify code sections.&amp;nbsp;&amp;nbsp; E.g.
    &lt;/p&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;    .pre
           Pre line 1
           Pre line 2
    .endpre
    
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


produces...&lt;br /&gt;&lt;br /&gt;
&lt;form mt:asset-id=&quot;219&quot; class=&quot;mt-enclosure mt-enclosure-image&quot; style=&quot;display: inline;&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/blogs/jim_clark/assets/pre.JPG&quot; alt=&quot;pre.JPG&quot; class=&quot;mt-image-none&quot; style=&quot;&quot; height=&quot;51&quot; width=&quot;115&quot; /&gt;&lt;/form&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;
and
    &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;    .code
    pdf = PDF::Writer.new
    pdf.select_font &amp;quot;Times-Roman&amp;quot;
    pdf.text &amp;quot;Hello Ruby&amp;quot;, :font =&amp;amp;gt;14, :justification =&amp;amp;gt; :left
    pdf.save_as(&amp;quot;e:/hello_ruby.pdf&amp;quot;)
    .endcode
    
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


produces...&lt;br /&gt;&lt;br /&gt;
&lt;form mt:asset-id=&quot;220&quot; class=&quot;mt-enclosure mt-enclosure-image&quot; style=&quot;display: inline;&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/blogs/jim_clark/assets/code.jpg&quot; alt=&quot;code.jpg&quot; class=&quot;mt-image-none&quot; style=&quot;&quot; height=&quot;73&quot; width=&quot;524&quot; /&gt;&lt;/form&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;
After you've created your content using the TechBook markup, it's easy to create a new instance of the PDF::TechBook class
and produce the PDF file.  The following is an example, where &quot;my_content&quot; is your marked-up content&lt;br /&gt;&lt;br /&gt;
    &lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;    pdf = PDF::TechBook.new
    pdf.select_font &amp;quot;Times-Roman&amp;quot;
    pdf.techbook_parse &amp;lt;span style=&amp;quot;color: blue;&amp;quot;&amp;gt;my_content&amp;lt;/span&amp;gt;
    pdf.save_as(&amp;quot;c:/temp/hello_ruby.pdf&amp;quot;)
    
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;



&lt;p&gt;
Download a sample program&amp;nbsp;&lt;/p&gt;&lt;form mt:asset-id=&quot;221&quot; class=&quot;mt-enclosure mt-enclosure-file&quot; style=&quot;display: inline;&quot; contenteditable=&quot;false&quot;&gt;&lt;a href=&quot;http://www.nearinfinity.com/blogs/my_pdf_writer.rb&quot;&gt;my_pdf_writer.rb&lt;/a&gt;&lt;/form&gt;&lt;p&gt;
&lt;/p&gt;

&lt;p&gt;There are other features supported by TechBook such as table of contents and the eval directive, but hopefully this
    will give you a start to using TechBook.  If you view the raw version of the PDF::Writer manual that comes with gem you can get a good idea of
    what you can accomplish with PDF::Writer.  &lt;br /&gt;&lt;br /&gt;
    I'm interested in other solutions. Leave me a comment if you know of other ways and/or better ways to create PDF documents
    using Ruby or have additional tips using PDF::Writer.
&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
</description>
        
          <category term="ruby" label="ruby"/>
        
      </item>
    
      <item>
        <title>Finding a Ruby IDE</title>
        <link>http://www.nearinfinity.com/blogs/jim_clark/finding_a_ruby_ide.html</link>
        <guid>http://www.nearinfinity.com/blogs/jim_clark/finding_a_ruby_ide.html</guid>
        <pubDate>Mon, 16 Apr 2007 21:49:33 -0400</pubDate>
        
        <author>Jim Clark</author>
        
        <description>&lt;p&gt;
  Recently I've spent some time revisiting and learning more about Ruby on
  Rails. In doing so I wanted a decent editor to work with.&amp;nbsp; This article
  is about my &quot;adventure&quot; in finding an editor and/or IDE that I could use in
  exploring and learning Ruby and Ruby on Rails and ultimately what I ended up
  selecting.&lt;br/&gt;
&lt;/p&gt;

&lt;p&gt;
  Everything I read online talked about
  &lt;a href=&quot;http://macromates.com/&quot; title=&quot;TextMate&quot;&gt;TextMate&lt;/a&gt; the editor of
  choice for Mac Ruby developers. I have a Windows machine so I didn't have that
  option. I decided to stick close to home by seeing if IntelliJ (my favorite
  Java editor) had a plug-in that supported Ruby. At the time no such plug-in
  existed. I gave SciTE and FreeRIDE (the editors that come with the Ruby
  distribution) a spin but wanted something a little closer to what I was use to
  in a Java IDE. I remember hearing something about RadRails, a Ruby IDE based
  on Eclipse. I was familiar enough with Eclipse so I decided to use that for my
  dabbling. I used this for a while and it was OK for what I was doing.&lt;br/&gt;
&lt;/p&gt;

&lt;p&gt;
  In the meantime I came across a Windows TextMate-like editor called &quot;e&quot;. I
  first installed a beta version of &quot;e&quot; which stands for the
  &quot;&lt;a href=&quot;http://e-texteditor.com/&quot; title=&quot;E Text Editor&quot;&gt;E Text Editor&lt;/a&gt; &quot;.
  I spent some time trying to make this editor work for me. I wanted to see what
  all the excitement was about in the TextMate world, even if it was on Windows
  :-) . To use &quot;e&quot; I first needed an updated installation of
  &lt;a href=&quot;http://www.cygwin.com&quot; title=&quot;cygwin&quot;&gt;cygwin&lt;/a&gt; since &quot;e&quot; relies on
  cygwin to function. I wasn't overly pleased that &quot;e&quot; relied on cygwin to be a
  functional editor. Nevertheless I installed a recent copy of cygwin and was up
  and running with &quot;e&quot;. &quot;e&quot; is in beta and with beta software comes annoyances
  and partially functional software. I really wanted to make this editor
  work.&amp;nbsp; However, I ran in to a few bugs that prohibited me from using &quot;e&quot;
  and caused me to resume using RadRails. About this time, the IntelliJ folks
  released a Ruby plug-in.
&lt;/p&gt;

&lt;p&gt;
  The IntelliJ plug-in worked fairly well for what I needed. I could use it in
  an environment that I was very familiar with and was happy to be &quot;home&quot;.
  Initially I experienced some minor bugs. The biggest problem I had was the
  plug-in can only be used in IntelliJ 6+ and I currently run 5.1 and wasn't
  prepared to upgrade. Unlike other editors I had looked at IntelliJ is
  relatively more expensive.&amp;nbsp; After my 30 day license expired, I headed
  back to RadRails, but then I ran in to this blog post about the future of
  RadRails:
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
  &quot;&lt;font face=&quot;Tahoma, sans-serif&quot;&gt;&lt;font color=&quot;#1f1f1f&quot;&gt;The bottom line to all
  of this is that Matt and I can't provide the same kind of commitment that we
  once could. Like or not, RadRails is not a business. We've been working our
  asses off on a start-up for the past few months and RadRails has suffered as a
  result. I wish things were different and we could sit back and work on open
  source all day but that is just not the reality anymore.&lt;/font&gt;&lt;/font&gt;&quot;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  I wanted to use software where I felt there was community support. I continued
  my search to see what else was available. I came across
  &lt;a href=&quot;http://intype.info/home/index.php&quot; title=&quot;InType&quot;&gt;InType&lt;/a&gt;, a very
  basic editor that is suppose to be TextMate-like, however, at the time of the
  writing they were still in an alpha version and didn't seem to have much
  momentum. At the time I used the software it was still very immature (e.g. no
  tab support though you can open multiple windows). Then one day I read a blog
  entry about Ruby support in NetBeans. IÃ•d always associated NetBeans with the
  so-so Java IDE currently produced by Sun.
&lt;/p&gt;

&lt;p&gt;
  I downloaded a
  &lt;a href=&quot;http://wiki.netbeans.org/wiki/view/MilestoneDownloads&quot; title=&quot;milestone release&quot;&gt;milestone
  release&lt;/a&gt; of NetBeans release 6 and installed support for Ruby and Ruby on
  Rails. Almost instantly I was wowed by their support for Ruby and Rails. I had
  no trouble becoming productive with the IDE and have been happy with the
  product since.&amp;nbsp; Current features include:
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    Code completion
  &lt;/li&gt;
  &lt;li&gt;
    Occurrence highlighting
  &lt;/li&gt;
  &lt;li&gt;
    Integrated documentation pop-ups for Ruby API calls
  &lt;/li&gt;
  &lt;li&gt;
    Parameter completion
  &lt;/li&gt;
  &lt;li&gt;
    Mongrel support
  &lt;/li&gt;
  &lt;li&gt;
    Rake migrations
  &lt;/li&gt;
  &lt;li&gt;
    And much
    &lt;a href=&quot;http://wiki.netbeans.org/wiki/view/RubyRecentChanges&quot; title=&quot;more&quot;&gt;more&lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
  Additionally, NetBeans supports development in either the reference
  implementation of Ruby or in
  &lt;a href=&quot;http://jruby.codehaus.org/&quot; title=&quot;JRuby&quot;&gt;JRuby&lt;/a&gt;, a Java
  implementation of the Ruby interpreter.&amp;nbsp; Most recently the NetBeans folks
  have begun adding
  &lt;a href=&quot;http://blogs.sun.com/tor/entry/ruby_screenshot_of_the_week7&quot; title=&quot;support&quot;&gt;support&lt;/a&gt;
  for TextMate bundles. They have also created a
  &lt;a href=&quot;http://deadlock.nbextras.org/hudson/job/ruby/&quot; title=&quot;stripped down version&quot;&gt;stripped
  down version&lt;/a&gt; of the IDE that is strictly for Ruby coding (though this
  still seems a little rough around the edges). As you can see the NetBeans
  folks are really putting forth a great deal of effort to create a solid,
  robust IDE for creating Ruby and Ruby on Rails applications. While the
  RadRails IDE is now supported by
  &lt;a href=&quot;http://www.aptana.com/&quot; title=&quot;Aptana&quot;&gt;Aptana&lt;/a&gt; and
  &lt;a href=&quot;http://www.jetbrains.com/idea/nextversion/&quot; title=&quot;IntelliJ 7&quot;&gt;IntelliJ
  7&lt;/a&gt; will include built in Ruby support (release expected by the end of the
  year), NetBeans has made a big leap ahead of the rest of the pack and nothing
  appears to be getting in their way. For now NetBeans is the choice for me when
  doing Ruby development.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Update: &lt;/strong&gt;I forgot to mention this recent &lt;a href=&quot;http://tnlessone.wordpress.com/2007/02/28/ruby-rails-ide-comparison-idea-netbeans-radrails/&quot;&gt;IDE comparison&lt;/a&gt; of NetBeans, IntelliJ and RadRails.
&lt;/p&gt;
</description>
        
          <category term="ruby" label="ruby"/>
        
      </item>
    
      <item>
        <title>IntelliJ Type Renderers</title>
        <link>http://www.nearinfinity.com/blogs/jim_clark/intellij_type_renderers.html</link>
        <guid>http://www.nearinfinity.com/blogs/jim_clark/intellij_type_renderers.html</guid>
        <pubDate>Wed, 04 Apr 2007 14:30:27 -0400</pubDate>
        
        <author>Jim Clark</author>
        
        <description>&lt;p&gt;
When debugging in &lt;a href=&quot;http://www.jetbrains.com/idea/&quot;&gt;IntelliJ&lt;/a&gt; you may need to inspect byte arrays as these byte arrays may contain meaningful text.  Out of the box individual byte array values will be rendered as numeric byte values.   This makes it difficult to decipher what it is you're debugging.
&lt;/p&gt;

&lt;form mt:asset-id=&quot;223&quot; class=&quot;mt-enclosure mt-enclosure-image&quot; style=&quot;display: inline;&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/blogs/jim_clark/assets/pre_renderer.gif&quot; alt=&quot;pre_renderer.gif&quot; class=&quot;mt-image-none&quot; style=&quot;&quot; height=&quot;252&quot; width=&quot;260&quot; /&gt;&lt;/form&gt;&lt;br /&gt;

&lt;p&gt;
Fortunately IntelliJ gives a way to customize your data views when debugging.  The way to handle this is create a custom Type Renderer.  While inspecting values during a debug session, in the Frame tab right click and select &quot;Customize Data Views...&quot;.  A dialog will appear, select the Type Renderers tab.  IntelliJ allows you to create a renderer for objects of a particular type.  Apply renderer to a byte[] and use the expression &quot;new String(this)&quot;.
&lt;/p&gt;

&lt;form mt:asset-id=&quot;224&quot; class=&quot;mt-enclosure mt-enclosure-image&quot; style=&quot;display: inline;&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/blogs/jim_clark/assets/customize_data_views.gif&quot; alt=&quot;customize_data_views.gif&quot; class=&quot;mt-image-none&quot; style=&quot;&quot; height=&quot;578&quot; width=&quot;665&quot; /&gt;&lt;/form&gt;&lt;br /&gt;

&lt;p&gt;&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;This will render the byte array as a String:
&lt;/p&gt;

&lt;form mt:asset-id=&quot;222&quot; class=&quot;mt-enclosure mt-enclosure-image&quot; style=&quot;display: inline;&quot; contenteditable=&quot;false&quot;&gt;&lt;img src=&quot;/blogs/jim_clark/assets/post_renderer.gif&quot; alt=&quot;post_renderer.gif&quot; class=&quot;mt-image-none&quot; style=&quot;&quot; height=&quot;243&quot; width=&quot;265&quot; /&gt;&lt;/form&gt;

&lt;p&gt;
For cases when you don't want this type renderer enabled, IntelliJ allows you to disable the renderer by unchecking the checkbox next to the renderer name.
&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
</description>
        
          <category term="java" label="java"/>
        
      </item>
    
      <item>
        <title>Thumbnail Generation Gotchas</title>
        <link>http://www.nearinfinity.com/blogs/jim_clark/thumbnail_generation_gotchas.html</link>
        <guid>http://www.nearinfinity.com/blogs/jim_clark/thumbnail_generation_gotchas.html</guid>
        <pubDate>Tue, 26 Dec 2006 15:21:48 -0500</pubDate>
        
        <author>Jim Clark</author>
        
        <description>&lt;p&gt;
    For a recent release of our software we had a requirement to generate and store thumbnail images.
    We have documents that come in to our system with image attachments and we need to generate a
    thumbnail image for each of the attachments that have a supported MIME type (gif, jpg, and png).
    When I signed up for this assignment I thought it was a good opportunity to re-learn JavaÃ•s image APIs (itÃ•s been
    almost seven years since doing any Swing or AWT work!). A lot of information is available on the web for generating
    thumbnail images, however, the information is scattered and there is more than one way to perform this task. Additionally, there are several gotchas 
    that I experienced rather than reading about.  Hopefully this article will get you started in the right direction and help you avoid
    some of the problems I faced.
&lt;/p&gt;


&lt;h2&gt;Scaling Images&lt;/h2&gt;

&lt;p&gt;
    Before reading and writing images, I first needed to figure out how to actually scale an image, i.e. take an
    original image and size it to an appropriate thumbnail size. Digging around the AWT package and the Image class
    I found the &lt;code&gt;java.awt.Image.getScaledInstance&lt;/code&gt; method. Piece of cake, just do something like:
&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;    &lt;span class=&quot;n&quot;&gt;Image&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scaledInstance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getScaledInstance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;thumbWidth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thumbHeight&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hint&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
    This worked fine and I used it for a couple of weeks when one of my &lt;a
        href=&quot;http://www.nearinfinity.com/blogs/page/jharwig&quot;&gt;coworkers&lt;/a&gt;
    pointed out that this was no longer the best way to scale images
    (see Bug &lt;a href=&quot;http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6196792&quot;&gt;6196792&lt;/a&gt;) Instead, use the 2D
    Graphics API and an
    &lt;a href=&quot;http://java.sun.com/j2se/1.4.2/docs/api/java/awt/geom/AffineTransform.html&quot;&gt;AffineTransform&lt;/a&gt; for a better solution.
&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BufferedImage&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getThumbnail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BufferedImage&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; 
                                         &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maxThumbWidth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; 
                                         &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maxThumbHeight&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; 
                                         &lt;span class=&quot;n&quot;&gt;RenderingHints&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hints&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;BufferedImage&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thumbnail&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;AffineTransform&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AffineTransform&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;// Determine scale so image is not larger than the max height and/or width. &lt;/span&gt;
       &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scaleToFit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getWidth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; 
                                 &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getHeight&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; 
                                 &lt;span class=&quot;n&quot;&gt;maxThumbWidth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maxThumbHeight&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                 
       &lt;span class=&quot;n&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

       &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getWidth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
       &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getHeight&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;thumbnail&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BufferedImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
               &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// don&amp;#39;t allow width to be less than 1&lt;/span&gt;
               &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// don&amp;#39;t allow height to be less than 1&lt;/span&gt;
               &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BufferedImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;TYPE_CUSTOM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; 
                                  &lt;span class=&quot;n&quot;&gt;BufferedImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;TYPE_INT_RGB&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;Graphics2D&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g2d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thumbnail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;createGraphics&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;g2d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setRenderingHints&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hints&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;g2d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;drawImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;g2d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dispose&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thumbnail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;scaleToFit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;w1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
    Using this code I was able to scale an image, i.e. create a thumbnail, and now I needed to save it.
&lt;/p&gt;


&lt;h2&gt;Storing Thumbnails&lt;/h2&gt;

&lt;p&gt;
    Since I was working with J2SE 1.4, which only allows for creating images in JPEG and PNG formats, we decided to use the JPEG format for
    thumbnails for its smaller file size.  
    I needed a way to write my thumbnail to an output stream since we have a separate API for storing files. Fortunately
    the &lt;code&gt;javax.imageio.ImageIO&lt;/code&gt; package provided
    an easy way to create JPEG images and put the image in to an OutputStream:
&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;    &lt;span class=&quot;n&quot;&gt;ImageIO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;jpg&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myOutputStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
    I incorporated my changes in to the build and left for a week of training, everything seem to be working ok. Upon returning I found out that
    thumbnails were &quot;killing&quot; our system.
    Naturally, I questioned, &quot;are you sure itÃ•s thumbnails causing the problem?&quot; ItÃ•s just image creation. Sure enough, the problem was caused by
    thumbnail generation.  It turns out the garbage collector went in to full GC mode when thumbnails were being created, specifically when hundreds 
    or thousands of thumbnails were being generated. Ugh, back to the drawing board.
&lt;/p&gt;

&lt;p&gt;After a little research, it was discovered that there are memory leaks in SunÃ•s ImageIO JPEG libraries
    (&lt;a href=&quot;http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5015137&quot;&gt;Bug 5015137&lt;/a&gt;
    and &lt;a href=&quot;http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4827358&quot;&gt;Bug 4827358&lt;/a&gt;).
    As our system was creating hundreds of thumbnails, everything else came to a screeching halt thanks to garbage
    collection. What to do, what to do?
&lt;/p&gt;

&lt;p&gt;
    Supposedly these bugs are fixed in J2SE 1.5, however, upgrading wasn't an option.
&lt;/p&gt;
&lt;p&gt;
    One solution we looked at was creating thumbnails as PNG files. Fine, this works, no problems with performance.
    YouÃ•ll just need to go out and buy a few extra hard drives. I was finding the PNGs to be 4, 5, 6 times larger than
    JPEGs. I looked at ways to compress the PNGs via Java but didnÃ•t have much luck getting them down to a reasonable
    size.
&lt;/p&gt;

&lt;p&gt;
    We also talked about having the thumbnail creation occur offline after the document was brought in to our system.
    This seemed more complicated than we wanted to make it. Plus we were running out of time as the code deadline was
    approaching.
&lt;/p&gt;

&lt;p&gt;        
Next a coworker sent a snippet of code, for encoding images to JPEG, that talked directly to &lt;code&gt;com.sun&lt;/code&gt;
JPEG classes.  This always seemed a no-no, i.e. Sun says: &lt;em&gt;&quot;Note that the classes in the &lt;code&gt;com.sun.image.codec.jpeg&lt;/code&gt; 
package are not part of the core Java APIsÃ‰&quot;.&lt;/em&gt;
Since we werenÃ•t planning to upgrade the JDK any time soon we went with this approach for writing JPEGs.
&lt;/p&gt;
        
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;    &lt;span class=&quot;n&quot;&gt;JPEGImageEncoder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JPEGCodec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;createJPEGEncoder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myByteArrayOutputStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;JPEGEncodeParam&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encodeParams&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getDefaultJPEGEncodeParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;encodeParams&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setQuality&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;encoder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setJPEGEncodeParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encodeParams&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;encoder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
    Everyone was happy; we could create JPEG thumbnails by circumventing the ImageIO API and talking directly to the
    com.sun classes. UntilÃ‰
&lt;/p&gt;

&lt;h2&gt;Reading Images&lt;/h2&gt;

&lt;p&gt;
    I noticed that certain thumbnails werenÃ•t being rendered correctly; rather they were rendered as black rectangles.
&lt;/p&gt;
        
&lt;div style=&quot;background: black;height: 75px;width:100px&quot;&gt;&lt;/div&gt;        

&lt;p&gt;
    Now what? Was this something to do with the usage of the &lt;code&gt;JPEGImageEncoder&lt;/code&gt;, i.e. talking directly to the &lt;code&gt;com.sun&lt;/code&gt; classes? 
    After a little research it turns out the problem existed previously when directly using &lt;code&gt;ImageIO&lt;/code&gt; to encode and write images.
    Therefore, no new problems were introduced. It seemed to be a problem only with GIF files. I ran a couple of tests on
    Windows (dev environment) using my test GIFs and
    they worked fine. I tested animated GIF files on Windows and they worked correctly. I tested the animated GIFs on Solaris.
    These images were being rendered as black images. The animated GIF images that were &quot;thumbnailed&quot; on Solaris were not 
    created correctly.  I was now able to repeat the problem.
&lt;/p&gt;

&lt;p&gt;
    To read images from the file system, the images I would create thumbnails from, I was using the AWT tookit:
&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;    &lt;span class=&quot;n&quot;&gt;Image&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Toolkit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getDefaultToolkit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;createImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myFileBytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
    Unlike Windows, the Solaris toolkit apparently didnÃ•t know how to handle images that were made up of multiple images (GIF89a). I
    needed a way to create images, in my case from a byte array, that didn't result in a black image. Back to the ImageIO class. Turns out they have a &lt;code&gt;read&lt;/code&gt;
    method that can take an InputStream
&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;    &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ImageIO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ByteArrayInputStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myImageByteArray&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;
    However, I was a little leery of the ImageIO class due to the problems I had seen with the &lt;code&gt;write&lt;/code&gt; method.
    I did find a bug related to &lt;code&gt;ImageIO.read&lt;/code&gt; method (&lt;a href=&quot;http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4867874&quot;&gt;Bug 4867874&lt;/a&gt;),
    but it pertained to JPEGs.
    I decided to use &lt;code&gt;ImageIO.read&lt;/code&gt; for GIF files and continue using the AWT toolkit for JPEGs and other types.  This was a fix
    for our black image problem.
&lt;/p&gt;

&lt;p&gt;
    It seems as if our thumbnail processing is working as expected and we havenÃ•t seen noticeable degradation in
    performance or the black image problem.
&lt;/p&gt;

&lt;p&gt;
    If youÃ•ll be doing image processing, such as thumbnail creation, make sure your application can handle the
    processing requirements.
    Test a worse case scenario, e.g. create 1000 thumbnails. Test with many different image samples with different image
    formats (e.g. animated gifs)
    and sizes (large image files). Unfortunately you'll have to actually view the images to verify expected output, but now you are 
    hopefully aware of some of the issues surrounding the generation of thumbnails using the ImageIO APIs and the AWT toolkit.
&lt;/p&gt;
</description>
        
          <category term="java" label="java"/>
        
      </item>
    
  </channel> 
</rss>

