<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>AirBlog - Home</title>
  <id>tag:blog.airbladesoftware.com,2008:mephisto/</id>
  <generator uri="http://mephistoblog.com" version="0.7.3">Mephisto Noh-Varr</generator>
  <link href="http://blog.airbladesoftware.com/feed/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://blog.airbladesoftware.com/" rel="alternate" type="text/html"/>
  <updated>2008-05-27T09:39:35Z</updated>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2008-05-22:56974</id>
    <published>2008-05-22T09:15:00Z</published>
    <updated>2008-05-27T09:39:35Z</updated>
    <category term="Client Work"/>
    <category term="Rails"/>
    <link href="http://blog.airbladesoftware.com/2008/5/22/gps-style-latitudes-and-longitudes-on-rails-forms" rel="alternate" type="text/html"/>
    <title>GPS-style Latitudes and Longitudes on Rails Forms</title>
<content type="html">
            &lt;h2&gt;The Problem&lt;/h2&gt;

&lt;div class=&quot;imagery&quot;&gt;
&lt;img title=&quot;Great circles&quot; src=&quot;/assets/2008/5/22/lat_long_200.jpg&quot; alt=&quot;Globe with great circles&quot; /&gt;
&lt;p class=&quot;caption&quot;&gt;Latitudes and Longitudes (credit: NASA)&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Quite a few plugins exist to help you geocode post codes or zipcodes, and calculate the distance between two points.  However few, if any, help you with latitudes and longitudes on forms, with input elements that match your GPS, and intelligent validation.&lt;/p&gt;

&lt;p&gt;This is now solved.&lt;/p&gt;

&lt;h2&gt;The Situation&lt;/h2&gt;

&lt;p&gt;I&#8217;m building a web application that holds cruising information for offshore sailors.  Much of the information is located, in the sense that it applies to a specific point on the Earth&#8217;s surface.  A report on an anchorage, for example, might say something like, &#8220;Beware the submerged rock to starboard at the entrance; strong katabatic winds in spring; herds of wildebeest ashore.&#8221;  So we need the sailors to supply latitudes and longitudes on most of the forms they fill in.&lt;/p&gt;

&lt;div class=&quot;imagery&quot;&gt;
&lt;img title=&quot;Offshore sailing&quot; src=&quot;/assets/2008/5/22/offshore_200.jpg&quot; alt=&quot;Offshore sailing&quot; /&gt;
&lt;p class=&quot;caption&quot;&gt;The only way to travel (credit: Horse&#8217;s Mouth)&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;The consensus among existing geo plugins is to treat latitudes and longitudes as floats, storing them in the database as decimals.  However that&#8217;s not how people handle latitudes and longitudes.  For excellent &lt;a href=&quot;http://www.amazon.co.uk/Longitude-Dava-Sobel/dp/1857025717&quot;&gt;historical reasons&lt;/a&gt;, we think in degrees, minutes and seconds.  Or, if you use a GPS &#8212; and all sailors do &#8212; degrees, minutes and decimal minutes (milli-minutes).&lt;/p&gt;

&lt;p&gt;If you want people to enter the latitude and longitude of an anchorage on your site, and to enter them correctly, you need to let them just read it off their GPS.  And if they enter an invalid value, you need to flag whether it&#8217;s the degrees, the minutes, or the milli-minutes &#8212; not simply say the whole lot &#8220;is invalid&#8221;.&lt;/p&gt;

&lt;h2&gt;The Solution&lt;/h2&gt;

&lt;p&gt;Buy the &lt;a href=&quot;http://peepcode.com/products/rails-2-plugin-patterns&quot;&gt;Rails 2 Plugin Patterns Peepcode PDF&lt;/a&gt;.  Using the PDF I was able to write the plugin right, first-time.  No trial and error: straight to the solution.  The time it saved was more than worth $9.  And the author&#8217;s a great guy ;-)&lt;/p&gt;

&lt;p&gt;So, install my &lt;a href=&quot;http://opensource.airbladesoftware.com/trunk/plugins/geo_tools/&quot;&gt;GeoTools plugin&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
$ script/plugin install http://opensource.airbladesoftware.com/trunk/plugins/geo_tools/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(I&#8217;ll move all my plugins to Git soon, but they&#8217;ll remain available in Subversion for the forseeable future.)&lt;/p&gt;

&lt;p&gt;Run a database migration to add latitudes and longitudes to the relevant tables.  Let&#8217;s say we are talking about buried treasure:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
  def self.up
    create_table :treasures do |t|
      t.string :name
      t.boolean :display_on_map, :default =&gt; true
      t.with_options :precision =&gt; 15, :scale =&gt; 10 do |c|
        c.decimal :latitude
        c.decimal :longitude
      end
      t.timestamps
    end
  end
&lt;/code&gt;&lt;/pre&gt;

&lt;div class=&quot;imagery&quot;&gt;
&lt;img title=&quot;Looking for treasure&quot; src=&quot;/assets/2008/5/22/pirates_of_caribbean_200.jpg&quot; alt=&quot;Looking for treasure (credit: Pirates of the Caribbean)&quot; /&gt;
&lt;p class=&quot;caption&quot;&gt;Show me the treasure&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Note we store latitudes and longitudes in the conventional way, so you can use other geo plugins too.&lt;/p&gt;

&lt;p&gt;Tell your models what to do:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
  class Treasure &amp;lt; ActiveRecord::Base
    acts_as_location
  end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Add latitude and longitude fields to your forms:&lt;/p&gt;

&lt;p&gt;&lt;br class=&quot;clear&quot; /&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;
&amp;lt;% form_for @treasure do |f| %&gt;
  &amp;lt;p&gt;
    &amp;lt;label for='treasure_name'&gt;Name&amp;lt;/label&gt;
    &amp;lt;%= f.text_field :name %&gt;
  &amp;lt;/p&gt;
  &amp;lt;p&gt;
    &amp;lt;label for='treasure_display_on_map'&gt;Display on map?&amp;lt;/label&gt;
    &amp;lt;%= f.check_box :display_on_map %&gt;
  &amp;lt;/p&gt;
  &amp;lt;p&gt;
    &amp;lt;label for='treasure_latitude'&gt;Latitude&amp;lt;/label&gt;
    &amp;lt;%= f.latitude_field :latitude %&gt;
  &amp;lt;/p&gt;
  &amp;lt;p&gt;
    &amp;lt;label for='treasure_longitude'&gt;Longitude&amp;lt;/label&gt;
    &amp;lt;%= f.longitude_field :longitude %&gt;
  &amp;lt;/p&gt;
&amp;lt;% end %&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Done.&lt;/p&gt;

&lt;p&gt;You can also easily display a latitude and longitude:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;
&amp;lt;p&gt;Name: &amp;lt;%=h @treasure.name %&gt;&amp;lt;/p&gt;
&amp;lt;p&gt;Location: &amp;lt;%= @treasure.location %&gt;&amp;lt;/p&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And that will produce:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;
&amp;lt;p&gt;Name: King Solomon's Mines&amp;lt;/p&gt;
&amp;lt;p&gt;Location: 12&amp;deg;34.567&amp;prime;S, 98&amp;deg;76.543&amp;prime;W&amp;lt;/p&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Bonus&lt;/h2&gt;

&lt;p&gt;Happily for you, my &lt;a href=&quot;http://opensource.airbladesoftware.com/trunk/plugins/air_budd_form_builder/README&quot;&gt;AirBudd accessible form builder plugin&lt;/a&gt; is fully compatible with &lt;a href=&quot;http://opensource.airbladesoftware.com/trunk/plugins/geo_tools/&quot;&gt;GeoTools&lt;/a&gt;.  So instead of the form shown above, you can write this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
&amp;lt;% airbudd_form_for @treasure do |f| %&gt;
  &amp;lt;%= f.text_field      :name %&gt;
  &amp;lt;%= f.check_box       :display_on_map %&gt;
  &amp;lt;%= f.latitude_field  :latitude %&gt;
  &amp;lt;%= f.longitude_field :longitude %&gt;
&amp;lt;% end %&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And that&#8217;s compatible with &lt;a href=&quot;http://haml.hamptoncatlin.com/&quot;&gt;HAML&lt;/a&gt; too.&lt;/p&gt;

&lt;p&gt;So now we have meaningful, GPS-style latitudes and longitudes with minimal effort.  And treasure.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2008-05-06:56413</id>
    <published>2008-05-06T14:51:00Z</published>
    <updated>2008-05-06T14:55:30Z</updated>
    <category term="Databases"/>
    <link href="http://blog.airbladesoftware.com/2008/5/6/relational-databases-are-not-relational" rel="alternate" type="text/html"/>
    <title>Relational Databases Are Not Relational</title>
<content type="html">
            &lt;p&gt;I&#8217;ve been meaning to write about this ever since reading &lt;a href=&quot;http://www.amazon.co.uk/Database-Depth-Relational-Theory-Practitioners/dp/0596100124/&quot;&gt;Databases in Depth&lt;/a&gt;, a punchy presentation of relational theory by &lt;a href=&quot;http://en.wikipedia.org/wiki/Edgar_F._Codd&quot;&gt;C.J.&amp;nbsp;Date&lt;/a&gt;.  I&#8217;m sure you already know this, but Date worked closely for many years with &lt;a href=&quot;http://en.wikipedia.org/wiki/Edgar_F._Codd&quot;&gt;E.F.&amp;nbsp;Codd&lt;/a&gt;, the man who introduced the relational model in his 1969 paper &lt;i&gt;Derivability, Redundancy, and Consistency of Relations Stored in Large Data Banks&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;Anyway, here are some highlights from the &lt;a href=&quot;http://www.amazon.co.uk/Database-Depth-Relational-Theory-Practitioners/dp/0596100124/&quot;&gt;book&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The term &#8220;relational&#8221; has nothing to do with relating two tables on a common set of columns.&lt;/li&gt;
&lt;li&gt;Relations are multi-dimensional.  Don&#8217;t let the term &#8220;table&#8221; fool you into thinking they are two-dimensional.&lt;/li&gt;
&lt;li&gt;Nulls are not values.&lt;/li&gt;
&lt;li&gt;SQL is not a set-oriented language (it is bag-oriented).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I used to think I had a pretty good understanding of databases until I read that &lt;a href=&quot;http://www.amazon.co.uk/Database-Depth-Relational-Theory-Practitioners/dp/0596100124/&quot;&gt;book&lt;/a&gt;.  Now at least I know how little I know.  I think that&#8217;s progress.&lt;/p&gt;

&lt;p&gt;If you work with databases — and that includes anybody writing Rails code — I recommend you read the &lt;a href=&quot;http://www.amazon.co.uk/Database-Depth-Relational-Theory-Practitioners/dp/0596100124/&quot;&gt;book&lt;/a&gt;.  Think of it as part of your edumacation.  After all, I doubt you&#8217;ve read many other database books recently :-)&lt;/p&gt;

&lt;p&gt;So why write this now?  Well, I was &lt;a href=&quot;http://blog.labnotes.org/2007/09/02/couchdb-thinking-beyond-the-rdbms/&quot; title=&quot;CouchDB - thinking beyond the RDBMS, by Tobias Lütke&quot;&gt;reading about CouchDB&lt;/a&gt; and found in the comments a highly intelligent&amp;sup1; contribution from somebody called Breton.  Here it is:&lt;/p&gt;

&lt;blockquote&gt;&lt;div&gt;
&lt;p&gt;There’s a few myths floating around in this article and in the comments. I normally don’t have much luck diffusing myths, but hopefully if the people read this have the ability to think critically, and do their own research instead of knee-jerk react, then it should go alright.&lt;/p&gt;

&lt;p&gt;Myth 1: SQL is relational. It turns out this is rubbish. SQL is so much &lt;em&gt;not&lt;/em&gt; relational that the committee in charge of SQL had to remove the words &#8220;relation&#8221; and &#8220;relational&#8221; from the standard. This is easily verified: find the standard and do a simple find. What’s not relational about it? In short: in SQL, tables and rows are not sets; the order of records and columns are significant; SQL allows duplicates, and introduces three valued logic with the NULL — all violations of the relational model which introduce bugs, inconsistencies, and a significant risk of data corruption.&lt;/p&gt;

&lt;p&gt;Myth 2: Relational Databases are flawed. Truth: There’s no way to know since there’s never been a widely used relational database. There are some who argue that should the relational model ever be implemented in a DBMS system, it would outperform current database systems in terms of speed and stability. It seems to me this is probably true, but then, what do I know? (Though some vendors claim that they produce relational database systems, this could not possibly be true as long as such systems use SQL).&lt;/p&gt;

&lt;p&gt;Myth 3: Systems like CouchDB are in every way better than relational database systems.&lt;/p&gt;

&lt;p&gt;Again, there’s no way to know since there isn&#8217;t a widely available and usable relational database. But a truly relational database system would hold significant advantages over a &#8220;flat&#8221; data storage system such as CouchDB. Assuming, of course, that it is utilized properly, a relational database is essentially a large scale inference engine. Meaning that if you can reason about a subject using formal logic, you can reason about data on the subject on a large scale using the relational algebra or relational calculus. This is amazingly powerful, but since most people never bother learning about the relational model they never take advantage of it.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;And then, to wrap it up:&lt;/p&gt;

&lt;blockquote&gt;&lt;div&gt;
&lt;p&gt;A good analogy might be claiming that Web Standards, semantic html, and seperation of presentation and content are unworthy concepts because they happen to be difficult to achieve in IE6. Don’t blame the inadequacies of the implementation on the concept itself.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;Indeedy.&lt;/p&gt;

&lt;p&gt;&amp;sup1; I know it was intelligent because it agreed with me.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2008-04-30:56096</id>
    <published>2008-04-30T08:14:00Z</published>
    <updated>2008-04-30T08:14:36Z</updated>
    <category term="Business"/>
    <category term="Quotations"/>
    <link href="http://blog.airbladesoftware.com/2008/4/30/small-business" rel="alternate" type="text/html"/>
    <title>Small Business</title>
<content type="html">
            &lt;blockquote&gt;&lt;div&gt;
&lt;p&gt;The silly thing is that a fair amount of these small businesses (10% or so) will end up growing into some pretty large companies. The doggy daycare that I take my dog to occasionally started out as just one guy with one location (he even slept on the floor next to the dogs for the first year). Now they’ve got more than a dozen locations in three states, and the guy is a millionaire.&lt;/p&gt;

&lt;p&gt;Just do what you love, and even if you’re not trying to become a millionaire, it might just happen anyways.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;cite&gt;&lt;a href=&quot;http://subwindow.com&quot;&gt;Erik Peterson&lt;/a&gt; commenting on &lt;a href=&quot;http://www.37signals.com/svn/posts/979-quit-your-job&quot;&gt;Quit your job!&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;Well, now I know what to do if the software doesn&#8217;t work out :-)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2008-04-18:55213</id>
    <published>2008-04-18T15:04:00Z</published>
    <updated>2008-04-18T15:05:10Z</updated>
    <category term="Productivity"/>
    <category term="Quotations"/>
    <link href="http://blog.airbladesoftware.com/2008/4/18/urgency" rel="alternate" type="text/html"/>
    <title>Urgency</title>
<content type="html">
            &lt;blockquote&gt;&lt;div&gt;
&lt;p&gt;Emergency is the only urgency&#8230;.If your deliveries are that critical to the hour or day, maybe you’re setting up false priorities and dangerous expectations.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;cite&gt;Jason Fried, &lt;a href=&quot;http://www.37signals.com/svn/posts/966-urgency-is-poisonous&quot;&gt;Urgency is poisonous&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2008-04-15:54951</id>
    <published>2008-04-15T08:21:00Z</published>
    <updated>2008-04-15T08:21:59Z</updated>
    <category term="Quotations"/>
    <category term="Ruby"/>
    <link href="http://blog.airbladesoftware.com/2008/4/15/static-typing" rel="alternate" type="text/html"/>
    <title>Static Typing</title>
<content type="html">
            &lt;blockquote&gt;&lt;div&gt;
&lt;p&gt;In most cases a statically typed language is a premature optimization that gets extremely much in the way of productivity.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;cite&gt;&lt;a href=&quot;http://ola-bini.blogspot.com/2008/04/pragmatic-static-typing.html&quot;&gt;Pragmatic Static Typing&lt;/a&gt;, Ola Bini&lt;/cite&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2008-04-09:54643</id>
    <published>2008-04-09T18:40:00Z</published>
    <updated>2008-04-09T18:50:01Z</updated>
    <category term="Ruby"/>
    <link href="http://blog.airbladesoftware.com/2008/4/9/i-have-seen-the-future-of-dance-music" rel="alternate" type="text/html"/>
    <title>I Have Seen The Future Of Dance Music</title>
<content type="html">
            &lt;div class=&quot;imagery&quot;&gt;
&lt;img title=&quot;Archaeopteryx&quot; src=&quot;/assets/2008/4/9/archaeopteryx_200.jpg&quot; alt=&quot;Archaeopteryx&quot; /&gt;
&lt;p class=&quot;caption&quot;&gt;Bird?  Dinosaur?  Dance music generator&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;And his name is &lt;a href=&quot;http://gilesbowkett.blogspot.com/&quot;&gt;Giles Bowkett&lt;/a&gt;.  Or, rather, its name is &lt;a href=&quot;http://archaeopteryx.rubyforge.org/svn/&quot;&gt;Archaeopteryx&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With more layers of indirection than Enron&#8217;s accounts, this is lambda central.  Unlike the accounts, this isn&#8217;t obfuscation &#8212; it&#8217;s &lt;em&gt;adaptability&lt;/em&gt;.  At its heart, &lt;a href=&quot;http://archaeopteryx.rubyforge.org/svn/&quot;&gt;Archaeopteryx&lt;/a&gt; is a probabilistic MIDI generator.  The lambdas vary the probabilities randomly, or perhaps probabilistically; it really depends on the last lambda.&lt;/p&gt;

&lt;p&gt;Anyway, don&#8217;t take my word for it.  Get yourself some &lt;a href=&quot;http://www.propellerheads.se/products/reason&quot; title=&quot;Reason: a virtual studio rack&quot;&gt;Reason&lt;/a&gt;, a copy of &lt;a href=&quot;http://www.amazon.co.uk/Practical-Ruby-Projects-Programmer-Professionals/dp/159059911X/&quot;&gt;Practical Ruby Projects&lt;/a&gt;, and &#8230; something else whose name I&#8217;ve forgotten (pipes &lt;a href=&quot;http://archaeopteryx.rubyforge.org/svn/&quot;&gt;Archaeopteryx&lt;/a&gt;&#8217;s output into &lt;a href=&quot;http://www.propellerheads.se/products/reason&quot; title=&quot;Reason: a virtual studio rack&quot;&gt;Reason&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Right now &lt;a href=&quot;http://archaeopteryx.rubyforge.org/svn/&quot;&gt;Archaeopteryx&lt;/a&gt; generates pretty convincing drum &amp;amp; bass, and techno too.  &lt;a href=&quot;http://gilesbowkett.blogspot.com/&quot;&gt;Giles&lt;/a&gt; has vision for this, so &lt;a href=&quot;http://gilesbowkett.blogspot.com/2008/02/archaeopteryx-ruby-midi-generator.html&quot; title=&quot;Archaeopteryx unveiled&quot;&gt;watch that space&lt;/a&gt;.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2008-04-08:54620</id>
    <published>2008-04-08T10:22:00Z</published>
    <updated>2008-04-14T12:03:49Z</updated>
    <category term="Conferences"/>
    <category term="Rails"/>
    <link href="http://blog.airbladesoftware.com/2008/4/8/scotland-on-rails-2008" rel="alternate" type="text/html"/>
    <title>Scotland on Rails 2008</title>
<content type="html">
            &lt;p&gt;&lt;em&gt;Update:&lt;/em&gt; &lt;a href=&quot;/assets/2008/4/14/Scotland_on_Rails_long_running_tasks.pdf&quot;&gt;here are my slides&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Well the last people I expected to see when I wandered down to breakfast on the first day were the Russian national women&#8217;s hockey team.&lt;/p&gt;

&lt;p&gt;This &lt;a href=&quot;http://scotlandonrails.com&quot;&gt;conference&lt;/a&gt; was very good.  I encountered a lot of intriguing new ideas, many friendly and interesting people with whom I&#8217;d love to spend more time, and (not at the conference) a cousin I last saw thirteen years ago in Western Australia!&lt;/p&gt;

&lt;div class=&quot;imagery&quot;&gt;
&lt;img title=&quot;Pollock Halls&quot; src=&quot;/assets/2008/4/8/pollock_halls_200.jpg&quot; alt=&quot;Pollock Halls&quot; /&gt;
&lt;p class=&quot;caption&quot;&gt;The venue next door&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;You can&#8217;t really go wrong holding a conference in Edinburgh.  It&#8217;s a magnificent city, and because my grandfather grew up there I can walk around telling myself I&#8217;m not a tourist (I tell myself a lot of things).  And you&#8217;re never far from a pub, er, castle.&lt;/p&gt;

&lt;h2&gt;BDD and SDD&lt;/h2&gt;

&lt;p&gt;The talks I heard were all good.  The most immediately useful to me were those on testing: &lt;a href=&quot;http://www.tammersaleh.com/&quot;&gt;Tammer Saleh&lt;/a&gt; on &lt;a href=&quot;http://thoughtbot.com/projects/shoulda&quot;&gt;behaviour driven development with Shoulda&lt;/a&gt;, &lt;a href=&quot;http://www.brynary.com/&quot;&gt;Bryan Helmkamp&lt;/a&gt; on &lt;a href=&quot;http://rspec.info/&quot;&gt;story driven development&lt;/a&gt; and &lt;a href=&quot;http://svn.eastmedia.net/public/plugins/webrat/README&quot;&gt;Webrat&lt;/a&gt;, and &lt;a href=&quot;http://www.theedgecase.com/&quot;&gt;Jim Weirich and Joe O&#8217;Brien&lt;/a&gt; on &lt;a href=&quot;http://onestepback.org/software/flexmock/&quot;&gt;mocking&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To date I&#8217;ve found writing tests irksome; worthwhile, but clunky.  However, I&#8217;ve been using old-school Test::Unit, so I think now it&#8217;s time to upgrade.  (Not convinced yet by SDD, but time will tell.)&lt;/p&gt;

&lt;h2&gt;Erlang/OTP&lt;/h2&gt;

&lt;div class=&quot;imagery&quot;&gt;
&lt;img title=&quot;Palm trees in the snow&quot; src=&quot;/assets/2008/4/8/edinburgh_snow_200.jpg&quot; alt=&quot;Palm trees in the snow&quot; /&gt;
&lt;p class=&quot;caption&quot;&gt;Picnic, anyone?&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;I was pleased &lt;a href=&quot;http://en.wikipedia.org/wiki/Erlang_%28programming_language%29&quot;&gt;Erlang/OTP&lt;/a&gt; slipped into the schedule.  &lt;a href=&quot;http://hypernumbers.com/about/&quot;&gt;Gordon Guthrie&lt;/a&gt; ran through the concepts and architecture of Erlang/OTP systems, locating them within their historical context.  Guthrie was surprisingly irreverent, and his talk was all the better for it.&lt;/p&gt;

&lt;p&gt;Apparently in the UK telephone system&#8217;s first year of operation on Erlang/OTP, its downtime was 31 milliseconds.  That&#8217;s 99.9999999% availability.  Respect.&lt;/p&gt;

&lt;h2&gt;JRuby&lt;/h2&gt;

&lt;p&gt;As somebody who spent five years writing J2EE applications, I have no desire to interact with the Java language again.  But the Java platform &#8212; that&#8217;s a different kettle of ball games.  The JVM, with its dynamic optimisation, native threading and tuned garbage collection, is a sophisticated and fast runtime environment.  A Java-based Ruby implementation can take full advantage of those capabilities.&lt;/p&gt;

&lt;p&gt;So although I don&#8217;t care that &lt;a href=&quot;http://jruby.codehaus.org/&quot;&gt;JRuby&lt;/a&gt; lets me write &lt;a href=&quot;http://java.sun.com/javase/6/docs/technotes/guides/swing/index.html&quot;&gt;Swing&lt;/a&gt; in Ruby, I sat up and listened when &lt;a href=&quot;http://headius.blogspot.com/&quot;&gt;Charles Oliver Nutter&lt;/a&gt; and &lt;a href=&quot;http://www.bloglines.com/blog/ThomasEEnebo&quot;&gt;Thomas Enebo&lt;/a&gt; showed a threaded Ruby program using all its machine&#8217;s cores.  And I was intrigued by the idea of Rails application deployment to a single &lt;a href=&quot;http://wiki.jruby.org/wiki/JRuby_on_Rails_in_GlassFish&quot;&gt;Glassfish&lt;/a&gt; process.&lt;/p&gt;

&lt;h2&gt;Big Names, Delivering&lt;/h2&gt;

&lt;div class=&quot;imagery&quot;&gt;
&lt;img title=&quot;More snow&quot; src=&quot;/assets/2008/4/8/more_edinburgh_snow_200.jpg&quot; alt=&quot;More snow&quot; /&gt;
&lt;p class=&quot;caption&quot;&gt;The weather begins to bite&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Other speakers that stood out for me were &lt;a href=&quot;http://onestepback.org/&quot;&gt;Jim Weirich&lt;/a&gt; on Ruby class design, &lt;a href=&quot;http://www.koziarski.com/&quot;&gt;Michael Koziarski&lt;/a&gt; speaking frankly about the quality of Rails&#8217; internals, and &lt;a href=&quot;http://rubypal.com/&quot;&gt;David Black&lt;/a&gt; with his extended music analogy.&lt;/p&gt;

&lt;h2&gt;Highlight&lt;/h2&gt;

&lt;p&gt;But the most stimulating talk was &lt;a href=&quot;http://gilesbowkett.blogspot.com/&quot;&gt;Giles Bowkett&lt;/a&gt;&#8217;s on &lt;a href=&quot;http://www.manning.com/herrington/&quot;&gt;code generation&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Metaprogramming&quot;&gt;metaprogramming&lt;/a&gt;.  Few could mash up so amusingly Archimedes, &lt;a href=&quot;http://en.wikipedia.org/wiki/Jessica_Alba&quot;&gt;Jessica Alba&lt;/a&gt;, respect for &lt;a href=&quot;http://en.wikipedia.org/wiki/Lisp_programming_language&quot;&gt;Lisp&lt;/a&gt;, disrespect for &lt;a href=&quot;http://lispers.org/&quot;&gt;Lispers&lt;/a&gt;, code generation and sombreros.  Superb.&lt;/p&gt;

&lt;h2&gt;Overall&lt;/h2&gt;

&lt;p&gt;I had a much better time at Scotland on Rails than at both RailsConfs Europe.  And this was only the first one.  I&#8217;m looking forward to Scotland on Rails 2009.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2008-04-07:54618</id>
    <published>2008-04-07T19:39:00Z</published>
    <updated>2008-04-07T19:42:00Z</updated>
    <category term="Conferences"/>
    <link href="http://blog.airbladesoftware.com/2008/4/7/the-highland-fling-2008" rel="alternate" type="text/html"/>
    <title>The Highland Fling 2008</title>
<content type="html">
            &lt;div class=&quot;imagery&quot;&gt;
&lt;a href=&quot;http://www.thehighlandfling.com/&quot;&gt;&lt;img title=&quot;The Highland Fling&quot; src=&quot;/assets/2008/4/7/highland_fling_155.png&quot; alt=&quot;The Highland Fling&quot; /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Pulled out of the bag at the eleventh hour by the inimitable &lt;a href=&quot;http://www.alanwhitewebdevelopment.com/&quot; title=&quot;Alan White Web Development&quot;&gt;Alan White&lt;/a&gt;, &lt;a href=&quot;http://www.thehighlandfling.com/&quot; title=&quot;The Highland Fling&quot;&gt;The Highland Fling&lt;/a&gt; was a fun, interesting one-day conference about &#8220;The Browser and Beyond&#8221;.&lt;/p&gt;

&lt;p&gt;Three features made the conference work so well: it was small, ensuring a convivial atmosphere; the talks came one after the other, not in parallel, so you didn&#8217;t miss anything; and the traditional Q&amp;amp;A was enlivened considerably by &lt;a href=&quot;http://www.boagworld.com/&quot; title=&quot;Boagworld&quot;&gt;Paul Boag&lt;/a&gt;&#8217;s compèring.&lt;/p&gt;

&lt;p&gt;The most intriguing talk for me was &lt;a href=&quot;http://www.slideshare.net/simon/comet-at-the-highland-fling/&quot; title=&quot;Simon Willison&#8217;s slides on Comet&quot;&gt;Simon Willison&#8217;s on Comet&lt;/a&gt;, a set of techniques for pushing live updates to web pages.  Calling them techniques lends thems an air of respectability but, in reality, these are a shifty bunch of hacks that mislead browsers in various startling ways.  Somehow, extraordinarily, this all works reliably, and across platforms too.  Even better, the nastiness has been swept under the carpet by the &lt;a href=&quot;http://dojotoolkit.org/&quot; title=&quot;Dojo Toolkit&quot;&gt;Dojo&lt;/a&gt; JavaScript library, which you can drop innocently into your webapp.&lt;/p&gt;

&lt;p&gt;Best of all, the &lt;a href=&quot;http://svn.xantus.org/shortbus/trunk/bayeux/bayeux.html&quot; title=&quot;The Bayeux protocol&quot;&gt;Bayeux protocol&lt;/a&gt; defines a standard communications protocol between Comet clients and Comet servers.  Immediately this separates the difficult, infrastructural parts of Comet from the rest of your application and, in theory, gives you implementation independence.&lt;/p&gt;

&lt;p&gt;Simon showed a few examples of Comet in action, including Google&#8217;s updating spreadsheets and his own slideshow tool.  HTTP&#8217;s client-request, server-response rhythm is so foundational that it seemed &lt;a href=&quot;http://www.quotationspage.com/quote/776.html&quot; title=&quot;Any sufficiently advance technology is indistinguishable from magic.&quot;&gt;almost magical&lt;/a&gt; watching changes made in one browser show up, without polling, in another.&lt;/p&gt;

&lt;p&gt;Of course, the nature of the technology requires many concurrent client-server connections, a profile for which general web servers such as Apache are not designed.  This, I think, is my excuse finally to wheel out an &lt;a href=&quot;http://cometdaily.com/2007/12/14/getting-started-with-comet-on-erlang/&quot; title=&quot;Comet on Erlang&quot;&gt;Erlang server&lt;/a&gt; to see for myself what Comet can do.&lt;/p&gt;

&lt;p&gt;It was also good to see the &lt;a href=&quot;http://www.freeagentcentral.com/?referrer=19b9fl58&quot; title=&quot;FreeAgent Central&quot;&gt;FreeAgent&lt;/a&gt; crew out in force, especially as they took me out for dinner afterwards.  Thanks!&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2008-04-07:54578</id>
    <published>2008-04-07T08:29:00Z</published>
    <updated>2008-04-07T08:30:15Z</updated>
    <category term="Client Work"/>
    <category term="Quotations"/>
    <link href="http://blog.airbladesoftware.com/2008/4/7/professionalism" rel="alternate" type="text/html"/>
    <title>Professionalism</title>
<content type="html">
            &lt;blockquote&gt;&lt;div&gt;
&lt;p&gt;Apart from the food, the great joy of French restaurants in England is French waiters who are serious professionals and do not try to be your friend.  They have been brought up to respect clients for being &lt;i&gt;exigeant&lt;/i&gt;, and to despise them for being undiscriminating.  So when the English describe a mediocre dish as &#8216;lovely&#8217; or &#8216;very nice&#8217; and never make a fuss about the &lt;i&gt;cuisson&lt;/i&gt; of their steak, they are treated with the &lt;i&gt;hauteur&lt;/i&gt; they deserve.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;cite&gt;&lt;a href=&quot;http://www.amazon.co.uk/Dossier-How-Survive-English/dp/0719568463/&quot; title=&quot;Le Dossier&quot;&gt;Le Dossier&lt;/a&gt;, Hortense de Monplaisir (translated by Sarah Long)&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;Hmm, I never thought I&#8217;d say this, but perhaps I need to act more like a Frenchman.  Not in despising people, but in trying to be your clients&#8217; or customers&#8217; friend.  Regularly not charging for small pieces of work soon adds up &#8212; or rather, it doesn&#8217;t &#8212; and does not pay the bills.&lt;/p&gt;

&lt;p&gt;And if I don&#8217;t value my time, nobody else will value it for me.&lt;/p&gt;

&lt;div class=&quot;imagery&quot;&gt;
&lt;img title=&quot;Reassuringly expensive&quot; src=&quot;/assets/2008/4/7/stella_artois.jpg&quot; alt=&quot;Reassuringly expensive&quot; /&gt;&lt;/a&gt;
&lt;p class=&quot;caption&quot;&gt;Reassuringly expensive&lt;/p&gt;
&lt;/div&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2008-04-02:54034</id>
    <published>2008-04-02T15:30:00Z</published>
    <updated>2008-04-02T15:30:44Z</updated>
    <category term="Client Work"/>
    <link href="http://blog.airbladesoftware.com/2008/4/2/henrik-knudsen-site-wins-award" rel="alternate" type="text/html"/>
    <title>Henrik Knudsen Site Wins Award</title>
<content type="html">
            &lt;div class=&quot;imagery&quot;&gt;
&lt;a href=&quot;http://www.henrikknudsen.com/&quot;&gt;&lt;img title=&quot;Henrik Knudsen&quot; src=&quot;/assets/2008/4/2/hk_200.png&quot; alt=&quot;Henrik Knudsen&quot; /&gt;&lt;/a&gt;
&lt;p class=&quot;caption&quot;&gt;Award-winning work&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;We were delighted to hear that the site we built for &lt;a href=&quot;http://www.henrikknudsen.com&quot; title=&quot;Henrik Knudsen&quot;&gt;Henrik Knudsen&lt;/a&gt;, an award-winning photographer, has itself won an award.&lt;/p&gt;

&lt;p&gt;Specifically, it was chosen for &lt;a href=&quot;http://www.pdnonline.com&quot; title=&quot;Photo District News&quot;&gt;PDN&lt;/a&gt;&#8217;s Photography Annual 2007, a collection of the best portfolio sites of professional photographers.&lt;/p&gt;

&lt;p&gt;Credit for the slick Flash front-end belongs to &lt;a href=&quot;http://www.homemaderobot.com&quot; title=&quot;Homemade Robot&quot;&gt;Homemade Robot&lt;/a&gt;.  We built a content management system to power the Flash; and a client management system, with private client areas, where Mr Knudsen can display his photoshoots to his clients.&lt;/p&gt;

&lt;p&gt;We&#8217;ve learned that a photographer demands rather more of an image uploader than a random forum user with a small passport photo.  We&#8217;re running a heavily customised version of &lt;a href=&quot;http://svn.techno-weenie.net/projects/plugins/attachment_fu/&quot; title=&quot;Attachment Fu&quot;&gt;attachment_fu&lt;/a&gt;, with &lt;a href=&quot;http://codeforpeople.com/lib/ruby/bj/&quot; title=&quot;Background Job&quot;&gt;Background Job&lt;/a&gt; doing sterling work in, well, the background.&lt;/p&gt;

&lt;p&gt;All in all, a good team effort.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2008-03-31:53966</id>
    <published>2008-03-31T18:07:00Z</published>
    <updated>2008-03-31T18:08:22Z</updated>
    <category term="Quotations"/>
    <link href="http://blog.airbladesoftware.com/2008/3/31/90-under-any-conditions" rel="alternate" type="text/html"/>
    <title>90% Under Any Conditions</title>
<content type="html">
            &lt;blockquote&gt;&lt;div&gt;
&lt;p&gt;I also came to realise that trying to nail everything perfect in training is pretty useless.  All you&#8217;re doing is learning to do statics in perfect conditions.  &#8230;Don&#8217;t even try to beat your record, instead force yourself to do a good, solid, 90% performance under any conditions.  Then try to create the perfect conditions in the competition.  Do your personal bests there.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;cite&gt;Jome, &lt;a href=&quot;http://hypoxic.blogspot.com/2005/08/post-competition-pondering.html&quot; title=&quot;Post Competition Pondering&quot;&gt;Post Competition Pondering&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2008-03-29:53912</id>
    <published>2008-03-29T11:11:00Z</published>
    <updated>2008-03-29T11:12:12Z</updated>
    <category term="Quotations"/>
    <link href="http://blog.airbladesoftware.com/2008/3/29/heathrow-terminal-5-debacle" rel="alternate" type="text/html"/>
    <title>Heathrow Terminal 5 Debacle</title>
<content type="html">
            &lt;p&gt;A passenger contemplates the &lt;a href=&quot;http://www.guardian.co.uk/business/2008/mar/29/britishairwaysbusiness.theairlineindustry&quot;&gt;failure of the multi-million pound baggage-handling computer system&lt;/a&gt; on Terminal 5&#8217;s first day:&lt;/p&gt;

&lt;blockquote&gt;&lt;div&gt;
&lt;p&gt;Perhaps they have mended the elastic band by now.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;cite&gt;Alan Bowman&lt;/cite&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2008-03-28:53897</id>
    <published>2008-03-28T16:18:00Z</published>
    <updated>2008-03-28T16:19:35Z</updated>
    <category term="Notes To Self"/>
    <link href="http://blog.airbladesoftware.com/2008/3/28/note-to-self-why-some-jpegs-don-t-render-in-firefox-or-ie" rel="alternate" type="text/html"/>
    <title>Note To Self: Why Some JPEGs Don't Render in Firefox or IE</title>
<content type="html">
            &lt;p&gt;If you find some of your JPEGs render in Safari but not in Firefox or IE, check the images&#8217; &lt;a href=&quot;http://en.wikipedia.org/wiki/Color_model&quot; title=&quot;Explanation of colour models&quot;&gt;colour models&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;They come in two flavours: &lt;a href=&quot;http://en.wikipedia.org/wiki/Color_model#RGB_color_model&quot; title=&quot;Explanation of RGB colour model&quot;&gt;RGB&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Color_model#CMYK_color_model&quot; title=&quot;Explanation of CMYK colour model&quot;&gt;CMYK&lt;/a&gt;.  Firefox and IE won&#8217;t render the latter.  Safari handles both.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2008-03-19:53246</id>
    <published>2008-03-19T11:51:00Z</published>
    <updated>2008-03-28T09:37:32Z</updated>
    <category term="Rails"/>
    <link href="http://blog.airbladesoftware.com/2008/3/19/moving-between-lists-with-acts_as_list" rel="alternate" type="text/html"/>
    <title>Moving Between Lists With acts_as_list</title>
<content type="html">
            &lt;p&gt;How do you move an item managed by &lt;code class=&quot;ruby&quot;&gt;acts_as_list&lt;/code&gt; from one parent to another?  Moving items within a list is well documented, but there&#8217;s scant information on moving between lists.&lt;/p&gt;

&lt;p&gt;I wrote about this &lt;a href=&quot;/2007/8/29/moving-an-acts_as_list-child-to-a-new-parent&quot; title=&quot;Moving An acts_as_list Child To A New Parent&quot;&gt;previously&lt;/a&gt; in a pre-Rails 2 world.  This is an update for Rails 2 and &#8212; happy days &#8212; it&#8217;s simpler.&lt;/p&gt;

&lt;h2&gt;Intra-List Movement&lt;/h2&gt;

&lt;p&gt;Here&#8217;s the basic set-up.  This is all you need for intra-list movement.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
class Category
  has_many :products, :order =&gt; :position
end

class Product
  belongs_to   :category
  acts_as_list :scope =&gt; :category
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Inter-List Movement&lt;/h2&gt;

&lt;p&gt;When we move a product between categories, we need first to remove it from its current category&#8217;s list; and afterwards to insert it at the correct position in its new category&#8217;s list.&lt;/p&gt;

&lt;p&gt;This is slightly tricky because the instance methods &lt;code class=&quot;ruby&quot;&gt;acts_as_list&lt;/code&gt; adds to your model update records in the database directly, triggering callbacks you don&#8217;t necessarily want triggered.&lt;/p&gt;

&lt;p&gt;So instead of using &lt;code class=&quot;ruby&quot;&gt;before_save&lt;/code&gt; and &lt;code class=&quot;ruby&quot;&gt;after_save&lt;/code&gt; callbacks to tinker with the old and new categories&#8217; lists, you need to get involved at the point where you change the product&#8217;s category.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
class Product
  belongs_to   :category
  acts_as_list :scope =&gt; :category

  def category_id=(category_id)
    p = position
    remove_from_list if (p &amp;&amp; valid?)
    super
    insert_at position_in_bounds(p) if (p &amp;&amp; valid?)
  end

  private

  def position_in_bounds(pos)
    length = category.products.length
    length += 1 unless category.products.include? self
    if pos &amp;lt; 1
      1
    elsif pos &gt; length
      length
    else
      pos
    end
  end
end    
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;The Controller&lt;/h2&gt;

&lt;p&gt;Assuming your GUI for editing a product has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a dropdown list of categories to which the product can belong;&lt;/li&gt;
&lt;li&gt;a dropdown list of positions within its category&#8217;s list;&lt;/li&gt;
&lt;li&gt;AJAX that refreshes the positions when a different category is chosen;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&#8212; then your controller would look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
class ProductsController
  def update
    @product = Product.find params[:id]
    new_position = params[:product].delete(:position).to_i
    if @product.update_attributes params[:product]
      @product.move_to_position new_position
      redirect_to product_url(@product)
    else
      @product.position = new_position
      render :action =&gt; 'edit'
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The only difference from a normal update is the special handling of position.  Why do we treat position differently?  Because &lt;code class=&quot;ruby&quot;&gt;acts_as_list&lt;/code&gt; executes SQL updates directly on the database, independently of our model&#8217;s updates.  We only want this under-the-covers SQL update to take place if the model&#8217;s own update goes through successfully.&lt;/p&gt;

&lt;p&gt;For this to work, we need to define one further method on our model.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
class Product
  def move_to_position(position)
    insert_at position_in_bounds(position)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;By its nature, &lt;code class=&quot;ruby&quot;&gt;acts_as_list&lt;/code&gt; needs to update multiple records when you change a model&#8217;s position.  This update saves your model, which may come at an inconvenient time for you.  It&#8217;s easier, therefore, to avoid the usual lifecycle callbacks and instead operate at the point where the parent is changed.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2008-03-14:52833</id>
    <published>2008-03-14T12:00:00Z</published>
    <updated>2008-03-14T12:02:26Z</updated>
    <category term="Rails"/>
    <link href="http://blog.airbladesoftware.com/2008/3/14/lrug-easy-background-tasks-in-rails" rel="alternate" type="text/html"/>
    <title>Easy Long-Running Tasks In Rails</title>
<content type="html">
            &lt;div class=&quot;imagery&quot;&gt;
&lt;a href=&quot;http://www.sessionshouse.com&quot;&gt;&lt;img title=&quot;The Old Sessions House&quot; src=&quot;/assets/2008/3/14/sessions_house.gif&quot; alt=&quot;The Old Sessions House&quot; /&gt;&lt;/a&gt;
&lt;p class=&quot;caption&quot;&gt;Contains 80 Ruby programmers&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;On Monday night I spoke at the &lt;a href=&quot;http://lrug.org&quot; title=&quot;London Ruby User Group&quot;&gt;London Ruby User Group&lt;/a&gt; on handling long-running tasks in Rails.  No fights broke out so I considered it a success.&lt;/p&gt;

&lt;p&gt;In a month or so, I&#8217;ll return to my people and give an expanded version at &lt;a href=&quot;http://scotlandonrails.com/&quot; title=&quot;Scotland on Rails&quot;&gt;Scotland on Rails&lt;/a&gt;.  The skepticism and incredulity I encountered at &lt;a href=&quot;http://lrug.org&quot; title=&quot;London Ruby User Group&quot;&gt;LRUG&lt;/a&gt; will guide me as I hone my material.&lt;/p&gt;

&lt;p&gt;I&#8217;m not posting my slides because, by design, they make no sense on their own.  If you&#8217;d like them anyway, &lt;a href=&quot;http://airbladesoftware.com/hire&quot;&gt;get in touch&lt;/a&gt; and I&#8217;ll send them to you.&lt;/p&gt;

&lt;p&gt;Incidentally, for anyone who was there, my conclusion was: &lt;a href=&quot;http://codeforpeople.rubyforge.org/svn/bj/trunk/README&quot; title=&quot;Background Job&quot;&gt;Background Job&lt;/a&gt;, also known as BJ, by &lt;a href=&quot;http://codeforpeople.com/&quot; title=&quot;Ara T Howard&quot;&gt;Ara T Howard&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here&#8217;s an example of &lt;a href=&quot;http://blarg.slackworks.com/posts/bj-makes-attachment_fu-happy&quot;&gt;using BJ to upload files to Amazon S3 via attachment_fu&lt;/a&gt;.&lt;/p&gt;
          </content>  </entry>
</feed>
