<?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>Mike's stuff &#187; computing</title>
	<atom:link href="http://www.mfischer.com/wordpress/topics/computing/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.mfischer.com/wordpress</link>
	<description>Things from Mike's brain.</description>
	<lastBuildDate>Sat, 26 Jun 2010 16:18:53 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Blog Bifurcation</title>
		<link>http://www.mfischer.com/wordpress/2010/01/31/blog-bifurcation/</link>
		<comments>http://www.mfischer.com/wordpress/2010/01/31/blog-bifurcation/#comments</comments>
		<pubDate>Mon, 01 Feb 2010 02:53:44 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[computing]]></category>

		<guid isPermaLink="false">http://www.mfischer.com/wordpress/?p=447</guid>
		<description><![CDATA[Originally this blog started out as a fairly personal journal, but has recently adopted a more technology-oriented theme. I plan to focus even more on technology blogging in the future, but I also want to occasionally blog about personal happenings, so I&#8217;ve decided to split my blog in two. This site, mfischer.com, will return to [...]]]></description>
			<content:encoded><![CDATA[<p>Originally this blog started out as a fairly personal journal, but has recently adopted a more technology-oriented theme. I plan to focus even more on technology blogging in the future, but I also want to occasionally blog about personal happenings, so I&#8217;ve decided to split my blog in two.</p>
<p>This site, <em><a href="http://mfischer.com/">mfischer.com</a></em>, will return to its roots as the personal blog about Mike Fischer. To publish my technology articles I&#8217;ve created a new blog under a new domain: <em><a href="http://thelastpixel.net/">thelastpixel.net</a></em>. I&#8217;ve just gotten started with it, but plan to post regularly on software development and other technology issues. If you&#8217;re interested, check it out and sign up for the RSS subscription! If not, just keep watching here for more non-technical news from my life&#8230;</p>
<p><a href="http://thelastpixel.net"><img src="http://www.mfischer.com/wordpress/wp-content/uploads/2010/01/the-last-pixel.png" alt="the-last-pixel" title="the-last-pixel" width="489" height="674" class="center size-full wp-image-449" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mfischer.com/wordpress/2010/01/31/blog-bifurcation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Essential Ruby on Rails plug-ins and gems</title>
		<link>http://www.mfischer.com/wordpress/2009/07/13/essential-ruby-on-rails-plug-ins-and-gems/</link>
		<comments>http://www.mfischer.com/wordpress/2009/07/13/essential-ruby-on-rails-plug-ins-and-gems/#comments</comments>
		<pubDate>Mon, 13 Jul 2009 23:19:35 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[computing]]></category>

		<guid isPermaLink="false">http://www.mfischer.com/?p=427</guid>
		<description><![CDATA[Now that I&#8217;ve been using Rails for a while, I&#8217;ve accumulated a few gems and plugins that I end up using over and over, so I thought I&#8217;d share a little about each. haml and sass I was sold on Sass from the first few minutes I used it. Sass lets you write CSS using [...]]]></description>
			<content:encoded><![CDATA[<p>Now that I&#8217;ve been using Rails for a while, I&#8217;ve accumulated a few gems and plugins that I end up using over and over, so I thought I&#8217;d share a little about each.</p>
<p><strong><a href="http://haml.hamptoncatlin.com/">haml</a> and <a href="http://haml.hamptoncatlin.com/docs/rdoc/classes/Sass.html">sass</a></strong></p>
<p>I was sold on Sass from the first few minutes I used it.  Sass lets you write CSS using a simplified abstraction format, and compiles your sass code into CSS.  Best of all, it can be used without Rails (or Ruby), so I&#8217;ve been using it with static web pages as well.  Here&#8217;s an excellent example from the sass web site:</p>
<p><img src="http://www.mfischer.com/wordpress/wp-content/uploads/2009/07/haml-sass.png" alt="haml-sass" title="haml-sass" width="502" height="336" class="aligncenter size-full wp-image-429" /></p>
<p>Haml does the same for HTML.  It took me a little longer to get used to, probably because it&#8217;s actually a replacement for HTML and Embedded Ruby (ERB).  Haml really cuts down on the amount of typing needed to generate HTML, auto-closes tags (based on indentation), and makes it far easier to see the structure of your document.  This snapshot from the haml page is a great demonstration:</p>
<p><img src="http://www.mfischer.com/wordpress/wp-content/uploads/2009/07/haml.png" alt="haml" title="haml" width="500" height="198" class="aligncenter size-full wp-image-432" /></p>
<p><strong><a href="http://agilewebdevelopment.com/plugins/friendly_id">friendly_id</a></strong></p>
<p>This extends Rails&#8217; RESTful resources by making URLs look &#8220;friendlier&#8221;, using a user-specified attribute of a model instead of the auto-generated numeric ID.  In other words, by simply adding a statement like <code>has_friendly_id :name</code> to a <em>users</em> model, friendly_id converts URLs from <code>http://my.site.com/users/17</code> into the much nicer <code>http://my.site.com/users/mike</code>.</p>
<p><a href="http://github.com/binarylogic/authlogic/tree/master"><strong>Authlogic</strong></a></p>
<p>This is the leading user authentication framework for Rails.  It you need to allow users to register, sign in, change passwords, use OpenID, user LDAP, etc., this is the plug-in for you.  It takes some time to learn how to integrate it, since each web site&#8217;s implementation is going to be a little different.</p>
<p><a href="http://github.com/mislav/will_paginate/tree/master"><strong>mislav-will_paginate</strong></a></p>
<p>This makes it dead simple to take a model with many records, and display it in pages, where you can control how many are displayed per page, and the style of the page links:</p>
<p><img src="http://www.mfischer.com/wordpress/wp-content/uploads/2009/07/pagination.png" alt="pagination" title="pagination" width="300" height="37" class="aligncenter size-full wp-image-439" /></p>
<p><a href="http://thoughtbot.com/projects/paperclip"><strong>thoughtbot-paperclip</strong></a></p>
<p>I&#8217;ve researched and tried many file upload/attachment gems but Paperclip is the one I settled on.  It seems to be the most actively maintained, and one of the most flexible.  File uploading is still not as easy as it should be, especially if you want to provide feedback during upload (usually via a Flash plugin) or allow multiple attachments to a model (usually with an associated polymorphic upload model).  Paperclip doesn&#8217;t do these things out of the box, but it&#8217;s possible to wrangle it into submission&#8230;</p>
<p><a href="http://github.com/brianjlandau/unobtrusive_date_picker/tree/master"><strong>unobtrusive_date_picker</strong></a></p>
<p>These days there&#8217;s no reason to make your users select a month, day, and year from three separate drop-down boxes, or type a date in some pre-determined format.  This plug-in automagically adds a pop-up calendar to your date selection input fields.</p>
<p><img src="http://www.mfischer.com/wordpress/wp-content/uploads/2009/07/date-picker.png" alt="date-picker" title="date-picker" width="470" height="303" class="aligncenter size-full wp-image-440" /></p>
<p><a href="http://ennerchi.com/projects/jrails"><strong>jRails</strong></a></p>
<p>When I started learning Javascript a few years ago, it was a huge pain in the neck.  I quickly came across <a href="http://www.prototypejs.org/">Prototype</a>, which made my life much easier.  Before I got too far along with that however, I found <a href="http://jquery.com/">jQuery</a> and fell instantly in love.  This was clearly the way Javascript programming was meant to be.  I used it for everything.  Then last year when I started learning Rails, I was a little disappointed to find that the javascript library built-in to Rails was Prototype.  Fortunately, others apparently had the same complaint, and created JRails, which integrates jQuery with Rails.</p>
<p><strong>Others</strong></p>
<p>There are a few other gems and plugins I use, but not as frequently.  They include: <a href="http://maruku.rubyforge.org/">Maruku</a>, <a href="http://opensoul.org/tags/acts_as_audited">acts_as_audited</a>, <a href="http://mechanize.rubyforge.org/mechanize/">mechanize</a>, and <a href="http://wiki.github.com/why/hpricot">hpricot</a>.</p>
<p>Am I missing out on any must-have gems or plug-ins?  Let me know in the comments!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mfischer.com/wordpress/2009/07/13/essential-ruby-on-rails-plug-ins-and-gems/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Multiple image upload and crop with Rails</title>
		<link>http://www.mfischer.com/wordpress/2009/02/02/multiple-image-upload-and-crop-with-rails/</link>
		<comments>http://www.mfischer.com/wordpress/2009/02/02/multiple-image-upload-and-crop-with-rails/#comments</comments>
		<pubDate>Tue, 03 Feb 2009 00:25:32 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[computing]]></category>

		<guid isPermaLink="false">http://www.mfischer.com/?p=356</guid>
		<description><![CDATA[For a project I&#8217;m currently working on, I needed a way to upload several photos to attach to a &#8220;dog&#8221; model, and allow easy cropping of the photos. In Ruby on Rails, this turned out to be harder than I expected. The main problems I encountered were: There are several attachment uploading plug-ins for Rails, [...]]]></description>
			<content:encoded><![CDATA[<p>For a project I&#8217;m currently working on, I needed a way to upload several photos to attach to a &#8220;dog&#8221; model, and allow easy cropping of the photos.  In Ruby on Rails, this turned out to be harder than I expected.</p>
<p>The main problems I encountered were:</p>
<ol>
<li>There are several attachment uploading plug-ins for Rails, like attachment_fu, Paperclip, or UploadColumn, with various features and complexities, but none had good references on handling multiple uploads associated with one model instance.</li>
<li>To add multiple attachments to an object requires a separate model for attachments, associated with the main model via a has_many/belongs_to relationship. This isn&#8217;t hard if the model views are kept separate and RESTful (create a new dog, then add a photo, then add another photo, etc).  That&#8217;s not a good user experience however &#8212; I want to be able to add a new dog, <em>and</em> upload many associated photos at the same time.</li>
<li>It turns out that complex forms to handle multiple associated models is pretty tricky in Rails (but should get better with Rails 2.3, coming soon).</li>
<li>I also wanted to let the user manually crop the photos after upload, to just select the dog&#8217;s face for example.</li>
</ol>
<p>After several weekends of experimenting, reading lots of blogs and tutorials, and playing with various plug-ins, I finally have a working solution I&#8217;m pretty happy with.  Here&#8217;s what I ended up doing:</p>
<ul>
<li>I&#8217;m using the <a href="http://www.thoughtbot.com/projects/paperclip">Paperclip</a> gem to handle the actual uploads.  The main reason I chose this over other options was that Paperclip lets me easily create additional &#8220;styles&#8221; of an uploaded photo, like a small thumbnail, a page-sized version, etc.</li>
<li>I&#8217;m using the <a href="http://jamesgolick.com/2007/12/5/introducing-attributefu-multi-model-forms-made-easy">attribute_fu</a> plug-in to handle the multi-model forms so I can upload any number of images at the same time as a new dog is created.</li>
<li>I&#8217;m using the <a href="http://www.defusion.org.uk/code/javascript-image-cropper-ui-using-prototype-scriptaculous/">jsCropperUI</a> JavaScript library to let the user select an area to crop.</li>
<li>Since Paperclip requires <a href="http://www.imagemagick.org/script/index.php">ImageMagick</a> to do its resizing, I installed <a href="http://rmagick.rubyforge.org/">RMagick</a> and use that for my cropping.</li>
</ul>
<h2>Getting started</h2>
<p>I have two models: &#8220;Dog&#8221; and &#8220;Upload&#8221;.  I started by calling my second model &#8220;Attachment&#8221;, but after running into problems, I learned that Paperclip uses that name internally and will not work correctly if you name your model &#8220;Attachment&#8221;.</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="color: #FCFFBA;">$ rails dogs
$ cd dogs
$ script<span style="color:#006600; font-weight:bold;color: #CCC;">/</span>plugin install git:<span style="color:#006600; font-weight:bold;color: #CCC;">//</span>github.<span style="color:#9900CC;color: #f6f;">com</span><span style="color:#006600; font-weight:bold;color: #CCC;">/</span>giraffesoft<span style="color:#006600; font-weight:bold;color: #CCC;">/</span>attribute_fu.<span style="color:#9900CC;color: #f6f;">git</span>
$ script<span style="color:#006600; font-weight:bold;color: #CCC;">/</span>generate model dog name:string
$ script<span style="color:#006600; font-weight:bold;color: #CCC;">/</span>generate model upload description:string dog_id:integer \
         photo_file_name:string photo_file_size:integer
$ script<span style="color:#006600; font-weight:bold;color: #CCC;">/</span>generate controller dogs
$ script<span style="color:#006600; font-weight:bold;color: #CCC;">/</span>generate controller uploads</pre></div></div>

<h2>Models</h2>
<p>The Dog model just has a name for now.  The Upload model will represent each uploaded photo.  It has a description which the user can enter, a dog_id foreign key, and two attributes for Paperclip: a photo_file_name string and a photo_file_size integer.  See the Paperclip documentation for more details on how these (and other) special attributes are used.</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="color: #FCFFBA;"><span style="color:#008000; font-style:italic;color: #CDC;"># models/dog.rb</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;color: #B83A24;">class</span> Dog <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">has_many</span> <span style="color:#ff3333; font-weight:bold;">:uploads</span>,
           <span style="color:#ff3333; font-weight:bold;">:attributes</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;color: #577A61;">true</span>,
           <span style="color:#ff3333; font-weight:bold;">:discard_if</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#CC0066; font-weight:bold;color: #8FB394;">proc</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#123;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">|</span>upload<span style="color:#006600; font-weight:bold;color: #CCC;">|</span> upload.<span style="color:#9900CC;color: #f6f;">photo_file_size</span>.<span style="color:#0000FF; font-weight:bold;color: #577A61;">nil</span>? <span style="color:#006600; font-weight:bold;color: #CCC;">&#125;</span>
<span style="color:#9966CC; font-weight:bold;color: #B83A24;">end</span></pre></div></div>

<p>I updated the Dog model to have many uploads.  The &#8220;:attributes&#8221; parameter is part of attribute_fu, and lets the Dog controller create associated models at the same time a new Dog is created.  The &#8220;:discard_if&#8221; tells attribute_fu not to create an associated model if certain conditions are met &#8212; in this case, if there&#8217;s no file that was uploaded.  This is needed because we may put many file upload fields in the &#8220;new Dog&#8221; form, but a user may only select one or two photos.  In that case, all the blank form elements would be submitted too, and created as empty Upload instances.</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="color: #FCFFBA;"><span style="color:#008000; font-style:italic;color: #CDC;">#models/upload.rb</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;color: #B83A24;">class</span> Upload <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">belongs_to</span> <span style="color:#ff3333; font-weight:bold;">:dog</span>
  has_attached_file <span style="color:#ff3333; font-weight:bold;">:photo</span>,
                    <span style="color:#ff3333; font-weight:bold;">:styles</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#123;</span>
                      <span style="color:#ff3333; font-weight:bold;">:thumb</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#91;</span><span style="color:#996600;color: #666666;">&quot;100x100&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:jpg</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#93;</span>,
                      <span style="color:#ff3333; font-weight:bold;">:pagesize</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#91;</span><span style="color:#996600;color: #666666;">&quot;500x400&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:jpg</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#93;</span>,
                    <span style="color:#006600; font-weight:bold;color: #CCC;">&#125;</span>,
                    <span style="color:#ff3333; font-weight:bold;">:default_style</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:pagesize</span>
<span style="color:#9966CC; font-weight:bold;color: #B83A24;">end</span></pre></div></div>

<p>This Upload model belongs_to a dog, to match the has_many association above.  &#8220;has_attached_file&#8221; is part of Paperclip, and the &#8220;photo&#8221; attribute must match the prefix of the database fields above (e.g. photo_file_name).  Paperclip can automatically re-size photos and keep multiple versions, based on the &#8220;styles&#8221; hash.  Here we create a small thumbnail, and a version good for embedding in web pages.  In both cases, the photo is converted to a JPEG if needed.  The original photo is stored with a style of &#8220;original&#8221;.</p>
<h2>Views</h2>
<p>The main view we&#8217;re concerned about is the &#8220;new dog&#8221; view.  This will give the user a form to add a new dog, and upload photos to associate with the dog.</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="color: #FCFFBA;"># views/dogs/new.html.erb
&nbsp;
&lt;h1&gt;New dog&lt;/h1&gt;
&nbsp;
<span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span> <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">form_for</span> <span style="color:#0066ff; font-weight:bold;color: #88f;">@dog</span>, <span style="color:#ff3333; font-weight:bold;">:html</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:multipart</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;color: #577A61;">true</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#125;</span> <span style="color:#9966CC; font-weight:bold;color: #B83A24;">do</span> <span style="color:#006600; font-weight:bold;color: #CCC;">|</span>f<span style="color:#006600; font-weight:bold;color: #CCC;">|</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
  <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">error_messages</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
&nbsp;
  &lt;p&gt;
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">label</span> <span style="color:#ff3333; font-weight:bold;">:name</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>&lt;br /&gt;
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">text_field</span> <span style="color:#ff3333; font-weight:bold;">:name</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
  &lt;/p&gt;
&nbsp;
  &lt;div id='uploads' style='border: 1px solid silver'&gt;
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">render_associated_form</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span>@dog.<span style="color:#9900CC;color: #f6f;">uploads</span>, <span style="color:#ff3333; font-weight:bold;">:new</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#006666;color: #DDD;">5</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
  &lt;/div&gt;
&nbsp;
  <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">add_associated_link</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span><span style="color:#996600;color: #666666;">'Add another photo'</span>, <span style="color:#0066ff; font-weight:bold;color: #88f;">@dog</span>.<span style="color:#9900CC;color: #f6f;">uploads</span>.<span style="color:#9900CC;color: #f6f;">build</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
&nbsp;
  &lt;p&gt;
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">submit</span> <span style="color:#996600;color: #666666;">&quot;Create&quot;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
  &lt;/p&gt;
<span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span> <span style="color:#9966CC; font-weight:bold;color: #B83A24;">end</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span></pre></div></div>

<p>The first part of the above view gives us a form for a new dog instance.  It also calls attribute_fu&#8217;s &#8220;render_associated_form&#8221; to create a nested form for upload instances. Here we create five blank instance forms. The instance forms are generated by a partial named after the associated model&#8230; in this case the partial is _upload.html.erb (below).  We also add a link to create additional file upload forms on the fly via attribute_fu JavaScript with the &#8220;add_associated_link&#8221; call.</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="color: #FCFFBA;"># views/dogs/_upload.html.erb
&nbsp;
&lt;p class='upload'&gt;
  &lt;label for=&quot;upload_description&quot;&gt;Description:&lt;/label&gt;
  <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">text_field</span> <span style="color:#ff3333; font-weight:bold;">:description</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
&nbsp;
  &lt;label for=&quot;upload_photo&quot;&gt;Photo:&lt;/label&gt;
  <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#5A0A0A; font-weight:bold;color: #9bf;">file_field</span> <span style="color:#ff3333; font-weight:bold;">:photo</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
&nbsp;
  <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">remove_link</span> <span style="color:#996600;color: #666666;">&quot;remove&quot;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
&lt;/p&gt;</pre></div></div>

<p>The partial is pretty standard, just a field for our photo description, and a file upload field.  The only unusual part is attribute_fu&#8217;s &#8220;remove_link&#8221; JavaScript call, which lets the user remove one of the photo upload forms.</p>
<p>Here&#8217;s what the completed form looks like:</p>
<p><img src="http://www.mfischer.com/wordpress/wp-content/uploads/2009/02/form-example.png" alt="New dog form" title="form-example" width="543" height="257" class="size-full wp-image-378" /></p>
<h2>Controllers</h2>
<p>The nice thing about attribute_fu is that no special controller logic is needed!  The dog controller is just a standard RESTful controller!  When the form is submitted, the dog instance is created, and all the associated upload instances are created simultaneously:</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="color: #FCFFBA;"><span style="color:#008000; font-style:italic;color: #CDC;"># controllers/dogs_controller.rb</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;color: #B83A24;">class</span> DogsController <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;</span> ApplicationController
&nbsp;
  <span style="color:#9966CC; font-weight:bold;color: #B83A24;">def</span> index
    <span style="color:#0066ff; font-weight:bold;color: #88f;">@dogs</span> = Dog.<span style="color:#9900CC;color: #f6f;">find</span> <span style="color:#ff3333; font-weight:bold;">:all</span>
  <span style="color:#9966CC; font-weight:bold;color: #B83A24;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;color: #B83A24;">def</span> <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">show</span>
    <span style="color:#0066ff; font-weight:bold;color: #88f;">@dog</span> = Dog.<span style="color:#9900CC;color: #f6f;">find</span> params<span style="color:#006600; font-weight:bold;color: #CCC;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:id</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#93;</span>
  <span style="color:#9966CC; font-weight:bold;color: #B83A24;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;color: #B83A24;">def</span> <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">new</span>
    <span style="color:#0066ff; font-weight:bold;color: #88f;">@dog</span> = Dog.<span style="color:#5A0A0A; font-weight:bold;color: #9bf;">new</span>
  <span style="color:#9966CC; font-weight:bold;color: #B83A24;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;color: #B83A24;">def</span> create
    <span style="color:#0066ff; font-weight:bold;color: #88f;">@dog</span> = Dog.<span style="color:#5A0A0A; font-weight:bold;color: #9bf;">new</span> params<span style="color:#006600; font-weight:bold;color: #CCC;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:dog</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#93;</span>
&nbsp;
    <span style="color:#9966CC; font-weight:bold;color: #B83A24;">if</span> <span style="color:#0066ff; font-weight:bold;color: #88f;">@dog</span>.<span style="color:#5A0A0A; font-weight:bold;color: #9bf;">save</span>
      <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">flash</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:notice</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#93;</span> = <span style="color:#996600;color: #666666;">'Dog was successfully created.'</span>
      <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">redirect_to</span> <span style="color:#0066ff; font-weight:bold;color: #88f;">@dog</span>
    <span style="color:#9966CC; font-weight:bold;color: #B83A24;">else</span>
      <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">render</span> <span style="color:#ff3333; font-weight:bold;">:action</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#996600;color: #666666;">&quot;new&quot;</span>
    <span style="color:#9966CC; font-weight:bold;color: #B83A24;">end</span>
  <span style="color:#9966CC; font-weight:bold;color: #B83A24;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;color: #B83A24;">end</span></pre></div></div>

<h2>Image cropping</h2>
<p>The last feature to add is the image cropping functionality.  We&#8217;re going to do this in the &#8220;edit upload&#8221; action.  The edit form will show the image, and let the user drag a rectangle around the region to crop.  The form will return the rectangle coordinates, and we&#8217;ll override the standard update_attributes method of the Upload model, to perform the crop.</p>
<p>In the main view template, I&#8217;m including the jsCropperUI JavaScript code and its dependencies.  The scripts go in the public/javascripts directory when you install the jsCropperUI code.</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="color: #FCFFBA;"># views/layouts/application.html.erb
&nbsp;
<span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">javascript_include_tag</span> <span style="color:#996600;color: #666666;">'cropper/lib/prototype.js'</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
<span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">javascript_include_tag</span> <span style="color:#996600;color: #666666;">'cropper/lib/scriptaculous.js?load=builder,dragdrop'</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
<span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">javascript_include_tag</span> <span style="color:#996600;color: #666666;">'cropper/cropper.js'</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span></pre></div></div>

<p>The &#8220;edit upload&#8221; view is a little complex.  Here&#8217;s how it&#8217;s put together:</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="color: #FCFFBA;"># view/uploads/edit.html.erb
&nbsp;
&lt;h1&gt;Editing upload&lt;/h1&gt;
&nbsp;
<span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span> <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">form_for</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span>@upload<span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span> <span style="color:#9966CC; font-weight:bold;color: #B83A24;">do</span> <span style="color:#006600; font-weight:bold;color: #CCC;">|</span>f<span style="color:#006600; font-weight:bold;color: #CCC;">|</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
  <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">error_messages</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
&nbsp;
  &lt;p&gt;
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">label</span> <span style="color:#ff3333; font-weight:bold;">:description</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>&lt;br /&gt;
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">text_field</span> <span style="color:#ff3333; font-weight:bold;">:description</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
  &lt;/p&gt;
&nbsp;
  &lt;!-- CROP FORM --&gt;
  &lt;div id='cropwrap'&gt;
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">image_tag</span> <span style="color:#0066ff; font-weight:bold;color: #88f;">@upload</span>.<span style="color:#9900CC;color: #f6f;">photo</span>.<span style="color:#9900CC;color: #f6f;">url</span>, <span style="color:#ff3333; font-weight:bold;">:id</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#996600;color: #666666;">'cropimage'</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
  &lt;/div&gt;
&nbsp;
  &lt;div id='cropresults'&gt;
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">label</span> <span style="color:#996600;color: #666666;">'x1'</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">text_field</span> <span style="color:#996600;color: #666666;">'x1'</span>, <span style="color:#ff3333; font-weight:bold;">:size</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#006666;color: #DDD;">6</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
    &lt;br /&gt;
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">label</span> <span style="color:#996600;color: #666666;">'y1'</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">text_field</span> <span style="color:#996600;color: #666666;">'y1'</span>, <span style="color:#ff3333; font-weight:bold;">:size</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#006666;color: #DDD;">6</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
    &lt;br /&gt;
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">label</span> <span style="color:#996600;color: #666666;">'width'</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">text_field</span> <span style="color:#996600;color: #666666;">'width'</span>, <span style="color:#ff3333; font-weight:bold;">:size</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#006666;color: #DDD;">6</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
    &lt;br /&gt;
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">label</span> <span style="color:#996600;color: #666666;">'height'</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">text_field</span> <span style="color:#996600;color: #666666;">'height'</span>, <span style="color:#ff3333; font-weight:bold;">:size</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#006666;color: #DDD;">6</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
    &lt;br /&gt;
  &lt;/div&gt; &lt;!-- cropresults --&gt;
  &lt;!-- END CROP FORM --&gt;
&nbsp;
  &lt;p&gt;
    <span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span>= f.<span style="color:#9900CC;color: #f6f;">submit</span> <span style="color:#996600;color: #666666;">&quot;Update&quot;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span>
  &lt;/p&gt;
<span style="color:#006600; font-weight:bold;color: #CCC;">&lt;%</span> <span style="color:#9966CC; font-weight:bold;color: #B83A24;">end</span> <span style="color:#006600; font-weight:bold;color: #CCC;">%&gt;</span></pre></div></div>

<p>In addition to the edit field for our model&#8217;s normal attributes (&#8220;description&#8221;, in this case), we also have fields for the geometry of our crop rectangle.  These fields will be filled in automatically by the jsCropperUI.  We also need to display the image we&#8217;re cropping, and identify it with a CSS ID so the jsCropperUI can attach to it.  To attach the jsCropperUI, we need to add some JavaScript to the page:</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="color: #FCFFBA;"><span style="color:#008000; font-style:italic;color: #CDC;"># view/uploads/edit.html.erb</span>
&nbsp;
<span style="color:#006600; font-weight:bold;color: #CCC;">&lt;</span>script type=<span style="color:#996600;color: #666666;">&quot;text/javascript&quot;</span> language=<span style="color:#996600;color: #666666;">&quot;JavaScript&quot;</span><span style="color:#006600; font-weight:bold;color: #CCC;">&gt;</span>
function onEndCrop<span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span> coords, dimensions <span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#123;</span>
  $<span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span> <span style="color:#996600;color: #666666;">'upload_x1'</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span>.<span style="color:#9900CC;color: #f6f;">value</span> = coords.<span style="color:#9900CC;color: #f6f;">x1</span>;
  $<span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span> <span style="color:#996600;color: #666666;">'upload_y1'</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span>.<span style="color:#9900CC;color: #f6f;">value</span> = coords.<span style="color:#9900CC;color: #f6f;">y1</span>;
  $<span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span> <span style="color:#996600;color: #666666;">'upload_width'</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span>.<span style="color:#9900CC;color: #f6f;">value</span> = dimensions.<span style="color:#9900CC;color: #f6f;">width</span>;
  $<span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span> <span style="color:#996600;color: #666666;">'upload_height'</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span>.<span style="color:#9900CC;color: #f6f;">value</span> = dimensions.<span style="color:#9900CC;color: #f6f;">height</span>;
<span style="color:#006600; font-weight:bold;color: #CCC;">&#125;</span>
&nbsp;
Event.<span style="color:#9900CC;color: #f6f;">observe</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span> window, <span style="color:#996600;color: #666666;">'load'</span>, function<span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#123;</span>
  <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">new</span> Cropper.<span style="color:#9900CC;color: #f6f;">Img</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span><span style="color:#996600;color: #666666;">'cropimage'</span>, <span style="color:#006600; font-weight:bold;color: #CCC;">&#123;</span>
    minWidth: <span style="color:#006666;color: #DDD;">50</span>,
    minHeight: <span style="color:#006666;color: #DDD;">50</span>,
    displayOnInit: <span style="color:#0000FF; font-weight:bold;color: #577A61;">true</span>,
    onEndCrop: onEndCrop
  <span style="color:#006600; font-weight:bold;color: #CCC;">&#125;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span>;
<span style="color:#006600; font-weight:bold;color: #CCC;">&#125;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span>;
<span style="color:#006600; font-weight:bold;color: #CCC;">&lt;/</span>script<span style="color:#006600; font-weight:bold;color: #CCC;">&gt;</span></pre></div></div>

<p>This attaches the jsCropperUI to the photo we want to edit, identified by the &#8220;cropimage&#8221; CSS ID.  It also sets up a callback function to set our form fields with values based on the crop coordinates.  Check the jsCropperUI documentation for more details.</p>
<p>Here&#8217;s what our page looks like:</p>
<p><img src="http://www.mfischer.com/wordpress/wp-content/uploads/2009/02/crop-example.png" alt="crop-example" title="crop-example" width="519" height="584" class="aligncenter size-full wp-image-385" /></p>
<p>There are two other things to be aware of here:</p>
<p>First, the &#8220;image_tag&#8221; is displaying the &#8220;:default&#8221; style of the uploaded image.  If you look back to the Upload model code above, that means it&#8217;s an image that&#8217;s been scaled down to at most 500&#215;400 pixels.  This is important, since we don&#8217;t want to display a full-sized image if someone&#8217;s uploaded a giant photo from a 10 megapixel digital camera!</p>
<p>Second, we&#8217;re telling the form helpers to create form fields for attributes like &#8220;x1&#8243; and &#8220;width&#8221;, which aren&#8217;t attributes of our Upload model.  To make this work, we need to add some virtual attributes to the model (virtual, because they&#8217;re not associated with any fields in our database table):</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="color: #FCFFBA;"><span style="color:#008000; font-style:italic;color: #CDC;"># models/upload/upload.rb</span>
&nbsp;
attr_accessor <span style="color:#ff3333; font-weight:bold;">:x1</span>, <span style="color:#ff3333; font-weight:bold;">:y1</span>, <span style="color:#ff3333; font-weight:bold;">:width</span>, <span style="color:#ff3333; font-weight:bold;">:height</span></pre></div></div>

<p>Now, when the form is submitted, the standard &#8220;update&#8221; action in the uploads controller will call &#8220;update_attributes&#8221;, just like any other form and controller:</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="color: #FCFFBA;"><span style="color:#008000; font-style:italic;color: #CDC;"># controllers/uploads_controller.rb</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;color: #B83A24;">def</span> <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">update</span>
  <span style="color:#0066ff; font-weight:bold;color: #88f;">@upload</span> = Upload.<span style="color:#9900CC;color: #f6f;">find</span> params<span style="color:#006600; font-weight:bold;color: #CCC;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:id</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#93;</span>
  <span style="color:#9966CC; font-weight:bold;color: #B83A24;">if</span> <span style="color:#0066ff; font-weight:bold;color: #88f;">@upload</span>.<span style="color:#9900CC;color: #f6f;">update_attributes</span> params<span style="color:#006600; font-weight:bold;color: #CCC;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:upload</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#93;</span>
    <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">flash</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:notice</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#93;</span> = <span style="color:#996600;color: #666666;">'Upload was successfully updated.'</span>
    <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">redirect_to</span> <span style="color:#0066ff; font-weight:bold;color: #88f;">@upload</span>
  <span style="color:#9966CC; font-weight:bold;color: #B83A24;">else</span>
    <span style="color:#5A0A0A; font-weight:bold;color: #9bf;">render</span> <span style="color:#ff3333; font-weight:bold;">:action</span> <span style="color:#006600; font-weight:bold;color: #CCC;">=&gt;</span> <span style="color:#996600;color: #666666;">&quot;edit&quot;</span>
  <span style="color:#9966CC; font-weight:bold;color: #B83A24;">end</span>
<span style="color:#9966CC; font-weight:bold;color: #B83A24;">end</span></pre></div></div>

<p>To make this actually crop the image, we need to override the update_attributes method in the upload model:</p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="color: #FCFFBA;"><span style="color:#008000; font-style:italic;color: #CDC;"># models/upload.rb</span>
&nbsp;
<span style="color:#CC0066; font-weight:bold;color: #8FB394;">require</span> <span style="color:#996600;color: #666666;">'RMagick'</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;color: #B83A24;">def</span> update_attributes<span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span>att<span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span>
&nbsp;
  <span style="color:#008000; font-style:italic;color: #CDC;"># Should we crop?</span>
  scaled_img = <span style="color:#6666ff; font-weight:bold;">Magick::ImageList</span>.<span style="color:#5A0A0A; font-weight:bold;color: #9bf;">new</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span><span style="color:#0000FF; font-weight:bold;color: #577A61;">self</span>.<span style="color:#9900CC;color: #f6f;">photo</span>.<span style="color:#9900CC;color: #f6f;">path</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span>
  orig_img = <span style="color:#6666ff; font-weight:bold;">Magick::ImageList</span>.<span style="color:#5A0A0A; font-weight:bold;color: #9bf;">new</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span><span style="color:#0000FF; font-weight:bold;color: #577A61;">self</span>.<span style="color:#9900CC;color: #f6f;">photo</span>.<span style="color:#9900CC;color: #f6f;">path</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:original</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span>
  scale = orig_img.<span style="color:#9900CC;color: #f6f;">columns</span>.<span style="color:#9900CC;color: #f6f;">to_f</span> <span style="color:#006600; font-weight:bold;color: #CCC;">/</span> scaled_img.<span style="color:#9900CC;color: #f6f;">columns</span>
&nbsp;
  args = <span style="color:#006600; font-weight:bold;color: #CCC;">&#91;</span> att<span style="color:#006600; font-weight:bold;color: #CCC;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:x1</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#93;</span>, att<span style="color:#006600; font-weight:bold;color: #CCC;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:y1</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#93;</span>, att<span style="color:#006600; font-weight:bold;color: #CCC;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:width</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#93;</span>, att<span style="color:#006600; font-weight:bold;color: #CCC;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:height</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#93;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#93;</span>
  args = args.<span style="color:#9900CC;color: #f6f;">collect</span> <span style="color:#006600; font-weight:bold;color: #CCC;">&#123;</span> <span style="color:#006600; font-weight:bold;color: #CCC;">|</span>a<span style="color:#006600; font-weight:bold;color: #CCC;">|</span> a.<span style="color:#5A0A0A; font-weight:bold;color: #9bf;">to_i</span> <span style="color:#006600; font-weight:bold;color: #CCC;">*</span> scale <span style="color:#006600; font-weight:bold;color: #CCC;">&#125;</span>
&nbsp;
  orig_img.<span style="color:#9900CC;color: #f6f;">crop</span>!<span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span><span style="color:#006600; font-weight:bold;color: #CCC;">*</span>args<span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span>
  orig_img.<span style="color:#9900CC;color: #f6f;">write</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span><span style="color:#0000FF; font-weight:bold;color: #577A61;">self</span>.<span style="color:#9900CC;color: #f6f;">photo</span>.<span style="color:#9900CC;color: #f6f;">path</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:original</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span>
&nbsp;
  <span style="color:#0000FF; font-weight:bold;color: #577A61;">self</span>.<span style="color:#9900CC;color: #f6f;">photo</span>.<span style="color:#9900CC;color: #f6f;">reprocess</span>!
  <span style="color:#0000FF; font-weight:bold;color: #577A61;">self</span>.<span style="color:#5A0A0A; font-weight:bold;color: #9bf;">save</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;color: #B83A24;">super</span><span style="color:#006600; font-weight:bold;color: #CCC;">&#40;</span>att<span style="color:#006600; font-weight:bold;color: #CCC;">&#41;</span>
<span style="color:#9966CC; font-weight:bold;color: #B83A24;">end</span></pre></div></div>

<p>What&#8217;s going on here?  We want to crop our original, high-resolution image, but we used a scaled down version in the jsCropperUI to select our crop rectangle. To adjust for that, we need to check the pixel width (&#8220;columns&#8221;) for the original and scaled images, and compute a scaling factor.  Next we prepare the four arguments for the RMagick crop function, which expects x1, y2, width, and height.  We create an array with the arguments, convert to integer (they&#8217;re still strings, since they came from a text field in the form), and scale them.  We can pass multiple arguments to a method by prefacing an array with an asterisk.  That&#8217;s something new I came across in this project, and I suspect may come in handy again some time.  The image is cropped, and then written back to disk, replacing the original.</p>
<p>&#8220;reprocess!&#8221; is a Paperclip method to re-generate thumbnails and other scaled versions of an image from the original.  And finally, we call the true &#8220;update_attributes&#8221; method to handle things like the &#8220;description&#8221; or other actual attributes of our model.</p>
<p>So there you have it&#8230; a framework to deal with multiple image uploads to an associated model, with user-selected cropping.</p>
<p>I&#8217;ve packaged up the example code <a href="http://github.com/greendog99/multiple_image_upload_crop_example/tree/master">into a GitHub repository</a>. It&#8217;s a fully functional Rails 2.2.2 app, assuming you have the Paperclip gem and RMagick already installed.</p>
<p>Comments and improvements are welcomed.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mfischer.com/wordpress/2009/02/02/multiple-image-upload-and-crop-with-rails/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>Ruby memory leakage</title>
		<link>http://www.mfischer.com/wordpress/2009/01/04/ruby-memory-leakage/</link>
		<comments>http://www.mfischer.com/wordpress/2009/01/04/ruby-memory-leakage/#comments</comments>
		<pubDate>Sun, 04 Jan 2009 21:49:27 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[computing]]></category>

		<guid isPermaLink="false">http://www.mfischer.com/?p=349</guid>
		<description><![CDATA[I&#8217;ve been working on a Ruby on Rails web application to track and compare Xbox player scores and achievements&#8212;a direct ripoff of a similar Perl/Mason app that Ty wrote. I recently discovered that the web site started getting very slow to respond, and Ruby was using up lots of memory. I did a fair bit [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working on a Ruby on Rails web application to track and compare Xbox player scores and achievements&mdash;a direct ripoff of a similar Perl/Mason app that Ty wrote.  I recently discovered that the web site started getting very slow to respond, and Ruby was using up lots of memory.</p>
<p>I did a fair bit of Google research into memory usage and garbage collection in Rails, but couldn&#8217;t find any smoking gun.  I did come across a really tiny <a href="http://github.com/binarylogic/memory_usage_logger/tree/master">Memory Usage Logger</a> for Rails, that just adds the process memory size to the server log after each request.  I added this handy code, and used the <a href="http://httpd.apache.org/docs/2.0/programs/ab.html">Apache Benchmarking Tool</a> to send several hundred web requests to my app, and graphed the results.  Memory was definitely increasing linearly with the number of requests.</p>
<p>After doing some basic troubleshooting and code analysis, I was getting nowhere.  Instead, I created a new, simple Rails app.  Just an empty app, with one model and controller generated with Rails&#8217;s scaffolding and default views.  This exhibited the same ever-growing memory problem.  Weird.  Rails is used widely for major web sites, so I knew this couldn&#8217;t be a widespread problem.  I next installed <a href="http://www.rubyenterpriseedition.com/">Ruby Enterprise Edition</a>, which was fortunately a fast and painless process.  When I restarted my application and re-ran my stress test, memory was completely flat!</p>
<p><img src="http://chart.apis.google.com/chart?chtt=Ruby+App+Memory+Usage&amp;chts=000000,12&amp;chs=500x250&amp;chf=bg,s,ffffff|c,s,ffffff&amp;chxt=x,y&amp;chxl=0:||1:|33,224.00|39,180.00|45,136.00&amp;cht=lc&amp;chd=t:0.00,.60,1.14,1.67,2.21,5.74,10.94,16.18,21.42,23.23,23.30,23.33,23.33,23.33,23.33,23.33,23.33,23.33,23.70,28.17,33.34,38.58,41.80,41.80,41.80,41.84,41.90,41.90,41.90,41.90,41.94,41.94,41.97,41.97,43.88,48.52,48.52,48.55,48.55,48.55,48.55,48.55,48.55,48.55,48.55,48.55,48.55,49.05,54.23,54.70,54.70,54.70,54.70,54.70,54.73,54.73,54.76,54.76,54.76,54.76,54.76,58.93,60.61,60.61,60.61,60.61,60.61,60.64,60.64,60.64,60.64,60.64,60.64,60.64,64.60,67.76,67.76,67.79,67.79,67.79,67.79,67.79,67.79,67.83,67.83,67.83,67.83,69.74,74.31,74.31,74.31,74.31,74.31,74.34,74.34,74.34,74.34,74.34,74.34,74.37,74.88,80.08,80.45,80.45,80.45,80.45,80.45,80.45,80.45,80.45,80.45,80.45,80.49,80.52,84.85,86.60,86.60,86.60,86.60,86.60,86.60,86.60,86.60,86.60,86.60,86.60,86.60,90.42,93.51,93.51,93.51,93.51,93.51,93.51,93.51,93.51,93.51,93.51,93.51,93.51,95.50,100.00,100.00,100.00,100.00|8.59,8.59,8.59,8.59,8.59,8.59,8.59,9.16,12.25,15.78,19.44,23.06,26.79,30.45,33.98,37.74,39.42,39.42,39.42,39.42,39.45,39.48,39.52,39.55,39.59,39.62,39.65,39.69,39.69,39.69,39.69,39.69,39.69,39.69,39.69,39.69,39.72,39.75,39.79,39.82,39.85,39.89,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.92,39.95,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99,39.99&amp;chdl=Ruby|REE&amp;chco=ff0000,0000ff&amp;chls=1,1,0|1,1,0" alt="Google Chart"/></p>
<p>I notice now that although both versions of ruby (standard and Enterprise Edition) are version 1.8.6, they are different patchlevels, so I&#8217;m not sure if the memory fix is due to REE or due to some more recent ruby patches.  Either way, I&#8217;ll probably stick with REE in the future.</p>
<p><img src="http://www.mfischer.com/wordpress/wp-content/uploads/2009/01/picture-2.png" alt="ruby-versions" title="ruby-versions" width="447" height="73" class="alignnone size-full wp-image-350" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mfischer.com/wordpress/2009/01/04/ruby-memory-leakage/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Not really silent</title>
		<link>http://www.mfischer.com/wordpress/2008/12/31/not-really-silent/</link>
		<comments>http://www.mfischer.com/wordpress/2008/12/31/not-really-silent/#comments</comments>
		<pubDate>Wed, 31 Dec 2008 19:21:01 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[computing]]></category>
		<category><![CDATA[gaming]]></category>
		<category><![CDATA[misc]]></category>

		<guid isPermaLink="false">http://www.mfischer.com/?p=347</guid>
		<description><![CDATA[It&#8217;s been quite a while since I&#8217;ve written anything here. It&#8217;s not that I&#8217;ve stopped being social online; rather I&#8217;ve been using Twitter so much that writing a full-on blog post has seemed both time-consuming and unnecessary. So what&#8217;s been going on? Three things mostly: work, xbox gaming, and Ruby on Rails programming. I&#8217;m happy [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been quite a while since I&#8217;ve written anything here.  It&#8217;s not that I&#8217;ve stopped being social online; rather I&#8217;ve been using <a href="http://twitter.com/MikeFischer">Twitter</a> so much that writing a full-on blog post has seemed both time-consuming and unnecessary.</p>
<p>So what&#8217;s been going on?  Three things mostly: work, xbox gaming, and Ruby on Rails programming.  I&#8217;m happy to say I&#8217;ve finally got RoR pretty well figured out, and have created some pretty neat stuff with it so far (mostly around xbox social networking).  My long-term goal is to use it the next time I re-design the <a href="http://www.lrr.org/">Lab Rescue</a> web site.</p>
<p>I&#8217;m off work this week, and it&#8217;s nice to relax at home, see family, visit friends, and generally relax.</p>
<p>Merry Christmas, Happy New Year!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mfischer.com/wordpress/2008/12/31/not-really-silent/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bad weekend for hard disks</title>
		<link>http://www.mfischer.com/wordpress/2008/08/24/bad-weekend-for-hard-disks/</link>
		<comments>http://www.mfischer.com/wordpress/2008/08/24/bad-weekend-for-hard-disks/#comments</comments>
		<pubDate>Mon, 25 Aug 2008 02:44:16 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[computing]]></category>

		<guid isPermaLink="false">http://www.mfischer.com/?p=283</guid>
		<description><![CDATA[The Linux server in the basement crashed Saturday, and after some diagnosis, it turned out to be a failed 500 GB internal hard disk. The drive was the &#8220;backup&#8221; disk for the two 250 GB data disks in the Linux server, our two MacBooks, my desktop Mac, as well as for a variety of content [...]]]></description>
			<content:encoded><![CDATA[<p>The Linux server in the basement crashed Saturday, and after some diagnosis, it turned out to be a failed 500 GB internal hard disk.  The drive was the &#8220;backup&#8221; disk for the two 250 GB data disks in the Linux server, our two MacBooks, my desktop Mac, as well as for a variety of content I have hosted elsewhere, such as mfischer.com (at techno&#8217;s co-lo), lrr.org (at <a href="http://bluehost.com/">bluehost.com</a>), etc.  I had <a href="http://www.rsnapshot.org/">rsnapshot</a> set up to make incremental backups of all these other disks every 4 hours to the 500 GB disk.  So, losing it wasn&#8217;t the end of the world, since it was just backups of the original data.  I went onto <a href="http://newegg.com/">NewEgg.com</a> on Saturday and ordered a new 1 TB disk for $139 including 3-day delivery.</p>
<p>A few minutes later, Kathie returned from <a href="http://dragonbites.blogspot.com/">Scott</a> and <a href="http://qiofse.stitchinplace.net/">Sue</a>&#8216;s, and announced that the hard disk in Scott&#8217;s MacBook had just died.  Interestingly, the hard disk in my MacBook (purchased the same day as Scott&#8217;s) failed about two months ago, a couple weeks before the 1-year warranty ended.</p>
<p>So, while anxiously waiting for my new 1 TB disk to ship so I could start keeping backups again, today <i>another</i> disk in the Linux server failed.  This time it was one of the two 250 GB disks.  Now, I have no backups, so the data is gone.  I did get lucky though, since it was the disk containing my music archive, which means all I have to do is <a href="http://www.mfischer.com/2007/11/21/mp3-metadata-tagging/">re-rip 600 CDs into FLAC format</a>.  Not fun, but also not very urgent.  The other 250 GB disk has all the important stuff&#8230; years of documents, photos, software I&#8217;ve developed, etc.  If that disk had failed instead of the music disk, I&#8217;d be in sad shape right now.</p>
<p>So, I spent the evening frantically backing up everything I could from the &#8220;important&#8221; disk to various other places in the house (spare space on the desktop Mac, laptops, etc.).  That&#8217;s done, so I&#8217;m at least going to sleep knowing I have a backup of the important stuff &#8220;just in case&#8221;.  I also ordered a second 1 TB disk which I&#8217;ll be putting in Scott&#8217;s house as an off-site backup.  Considering the cost of hard disks these days, it doesn&#8217;t hurt to be overly cautious.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mfischer.com/wordpress/2008/08/24/bad-weekend-for-hard-disks/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Blog: Smashing Magazine</title>
		<link>http://www.mfischer.com/wordpress/2008/08/22/blog-smashing-magazine/</link>
		<comments>http://www.mfischer.com/wordpress/2008/08/22/blog-smashing-magazine/#comments</comments>
		<pubDate>Fri, 22 Aug 2008 19:18:36 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[computing]]></category>
		<category><![CDATA[misc]]></category>
		<category><![CDATA[photography]]></category>

		<guid isPermaLink="false">http://www.mfischer.com/?p=282</guid>
		<description><![CDATA[I don&#8217;t intend for my blog to turn into a review of other blogs, but this one I just have to mention. I recently came across the Smashing Magazine &#8220;blog&#8221; while looking for some help with web design. The site has an incredible depth of information on web site design &#8212; an area where I [...]]]></description>
			<content:encoded><![CDATA[<p>I don&#8217;t intend for my blog to turn into a review of other blogs, but this one I just have to mention.  I recently came across the <a href="http://www.smashingmagazine.com/">Smashing Magazine</a> &#8220;blog&#8221; while looking for some help with web design.  The site has an incredible depth of information on web site design &#8212; an area where I feel woefully inadequate, but desperately wish I was better at.  However, it also has lots of other interesting articles that set it apart.  Here&#8217;s a smattering of ones I&#8217;ve found interesting so far, but there are hundreds of similar articles on the site:</p>
<ul>
<li><a href="http://www.smashingmagazine.com/2008/08/03/35-beautiful-music-album-covers/">35 Beautiful Music Album Covers</a></li>
<li><a href="http://www.smashingmagazine.com/2008/04/28/really-stunning-pictures-and-photos/">(Really) Stunning Pictures and Photos</a></li>
<li><a href="http://www.smashingmagazine.com/2008/01/31/10-principles-of-effective-web-design/">10 Principles Of Effective Web Design</a></li>
<li><a href="http://www.smashingmagazine.com/2008/08/13/top-10-css-table-designs/">Top 10 CSS Table Designs</a></li>
<li><a href="http://www.smashingmagazine.com/2008/01/04/frameworks-round-up-when-to-use-how-to-choose/">Framewords Round-Up: When To Use, How To Choose?</a></li>
<li><a href="http://www.smashingmagazine.com/2008/07/02/55-free-high-quality-icon-sets/">55 Free High Quality Icon Sets</a></li>
</ul>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mfischer.com/wordpress/2008/08/22/blog-smashing-magazine/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby on Rails</title>
		<link>http://www.mfischer.com/wordpress/2008/08/07/ruby-on-rails/</link>
		<comments>http://www.mfischer.com/wordpress/2008/08/07/ruby-on-rails/#comments</comments>
		<pubDate>Fri, 08 Aug 2008 00:10:46 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[computing]]></category>

		<guid isPermaLink="false">http://www.mfischer.com/?p=281</guid>
		<description><![CDATA[For the past few weeks I&#8217;ve been teaching myself how to program in Ruby and Rails. Given that it&#8217;s hyped as &#8220;web development that doesn&#8217;t hurt&#8221; and is supposed to be easy to learn, I&#8217;ve been having more trouble than I expected. Two years ago I learned PHP in a week or so, and last [...]]]></description>
			<content:encoded><![CDATA[<p>For the past few weeks I&#8217;ve been teaching myself how to program in <a href="http://www.ruby-lang.org/">Ruby</a> and <a href="http://www.rubyonrails.org/">Rails</a>.  Given that it&#8217;s hyped as &#8220;web development that doesn&#8217;t hurt&#8221; and is supposed to be easy to learn, I&#8217;ve been having more trouble than I expected.  Two years ago I learned PHP in a week or so, and last year Javascript in a few weeks.  The Ruby language itself isn&#8217;t the problem, as it&#8217;s similar enough to many other languages I&#8217;ve used in the past.  Rails however is a dramatic departure from anything I&#8217;ve used in the past.  It&#8217;s a programming framework for rapidly developing easily maintainable web applications, and is &#8220;opinionated&#8221; software &#8212; that is, it has a specific way it wants you (and often forces you) to program, including variable names, filenames, breaking a project into a set of <i>models</i>, <i>controllers</i>, and <i>views</i>, etc.</p>
<p>There are hundreds of Rails tutorials all over the web, but they&#8217;re all very similar to each other, and just cover the basics. I&#8217;ve come to the conclusion that at least part of my problem is that I don&#8217;t have a good learning and reference book.  <i>Agile Web Development with Rails</i> is the definitive work, but the currently available edition only covers an old version of Rails, and the updated edition won&#8217;t be printed until October.  So, until then I&#8217;ll continue stumbling through my first project, learning a little bit at a time.</p>
<p>On the bright side, I&#8217;ve seen enough to be confident that once I <i>do</i> become proficient, I&#8217;ll be able to use Rails to develop web applications more easily (and with less errors) than I did in the past with PHP.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mfischer.com/wordpress/2008/08/07/ruby-on-rails/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Safari vs. Firefox</title>
		<link>http://www.mfischer.com/wordpress/2008/02/09/safari-vs-firefox/</link>
		<comments>http://www.mfischer.com/wordpress/2008/02/09/safari-vs-firefox/#comments</comments>
		<pubDate>Sat, 09 Feb 2008 22:48:54 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[computing]]></category>

		<guid isPermaLink="false">http://www.mfischer.com/2008/02/09/safari-vs-firefox/</guid>
		<description><![CDATA[I&#8217;ve been a Firefox user&#8230; for as long as I can remember. It started because I was a Windows user, and FF was vastly better than Internet Explorer (and still is). Since switching to Mac about two years ago, I&#8217;ve stayed with Firefox. I gave Apple&#8217;s Safari browser a few tries now and then, but [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been a Firefox user&#8230; for as long as I can remember.  It started because I was a Windows user, and FF was vastly better than Internet Explorer (and still is).  Since switching to Mac about two years ago, I&#8217;ve stayed with Firefox.  I gave Apple&#8217;s Safari browser a few tries now and then, but always ran into major complaints with how it worked, and didn&#8217;t see the need to investigate them.</p>
<p>Since I know most Mac people use Safari, and a fair number of &#8220;people who know what they&#8217;re doing&#8221; use it, I&#8217;m going to give it another try.  One of my favorite things about Firefox is its plug-in architecture, allowing anyone to develop very useful add-ins to the program.  Firebug is essential for any web developer, so unless Safari has something similar, I&#8217;ll still be falling back on Firefox for development.</p>
<p>Do you have any preferences one way or another?</p>
<p><code>$x = open(can_of($worms));<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mfischer.com/wordpress/2008/02/09/safari-vs-firefox/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>User interfaces gone bad</title>
		<link>http://www.mfischer.com/wordpress/2007/12/13/user-interfaces-gone-bad/</link>
		<comments>http://www.mfischer.com/wordpress/2007/12/13/user-interfaces-gone-bad/#comments</comments>
		<pubDate>Thu, 13 Dec 2007 19:36:15 +0000</pubDate>
		<dc:creator>mike</dc:creator>
				<category><![CDATA[computing]]></category>

		<guid isPermaLink="false">http://www.mfischer.com/2007/12/13/user-interfaces-gone-bad/</guid>
		<description><![CDATA[Microsoft Office 2008 for Mac is finished. They&#8217;re pressing CDs now and will begin shipping in mid-January. I&#8217;ve been looking forward to this release for a while, mainly because everyone else in the universe uses Office, so if I want to (successfully) view their documents, and have them view mine, I need to use Office. [...]]]></description>
			<content:encoded><![CDATA[<p>Microsoft Office 2008 for Mac is finished.  They&#8217;re pressing CDs now and will begin shipping in mid-January.  I&#8217;ve been looking forward to this release for a while, mainly because everyone else in the universe uses Office, so if I want to (successfully) view their documents, and have them view mine, I need to use Office.  I tried Apple&#8217;s new iWork suite, and it&#8217;s nice, but it had a lot of trouble with the Office documents I tried to open.  The current Office suite for Mac is Office 2004, and only exists for PowerPC processors, so on all the new Intel-based Macs (like ours), it runs in slow PowerPC emulation mode.  I did order Office 2008, mainly because of the too-good-to-refuse deal Microsoft ran the day after thanksgiving (buy Office 2004 now, get $100 off, and get a free upgrade to 2008 in January), which resulted in me getting Office 2008 for $25 plus shipping.</p>
<p>Anyway, the real point of this post is to share how sad I am at the Frankenstein user-interface of the new Office&#8230; a half-MacOS interface with a half-Vista interface glued on.  This on the same day that I read an article about glow-in-the-dark cats being bred by inserting jellyfish genes into their DNA.  I don&#8217;t think the cats or the software are better off.  And what&#8217;s with that floppy-disk &#8220;save&#8221; icon??  Has anyone even <em>seen</em> a floppy disk in the last 8 years?  What makes this more amusing is that the Office team did change the floppy disk icon as compared to the previous version of Office for Mac, and compared to the latest Windows Office: the new floppy icon is anatomically correct, whereas the previous versions had the aluminum access door on the wrong side as compared to a real disk.  Well, all I can say is I&#8217;m glad they got that fixed!</p>
<p><img src='http://www.mfischer.com/wordpress/wp-content/uploads/2007/12/office-2008-mac.jpg' alt='office-2008-mac.jpg' /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.mfischer.com/wordpress/2007/12/13/user-interfaces-gone-bad/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
<!-- WP Super Cache is installed but broken. The path to wp-cache-phase1.php in wp-content/advanced-cache.php must be fixed! -->