<?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,2009:mephisto/</id>
  <generator version="0.7.3" uri="http://mephistoblog.com">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>2009-06-23T09:56:41Z</updated>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2009-06-23:88124</id>
    <published>2009-06-23T09:56:00Z</published>
    <updated>2009-06-23T09:56:41Z</updated>
    <category term="Rails"/>
    <link href="http://blog.airbladesoftware.com/2009/6/23/a-paper-trail-for-your-models" rel="alternate" type="text/html"/>
    <title>A Paper Trail For Your Models</title>
<content type="html">
            &lt;p&gt;&lt;a href=&quot;http://github.com/airblade/paper_trail/tree/master&quot;&gt;PaperTrail&lt;/a&gt; lets you track changes to your Rails app&#8217;s models&#8217; data.  It&#8217;s good for auditing or versioning.  You can see how a model looked at any stage in its lifecycle and even undelete it after it&#8217;s been destroyed.&lt;/p&gt;

&lt;h2&gt;Features&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Stores every create, update and destroy.&lt;/li&gt;
&lt;li&gt;Does not store updates which don&#8217;t change anything.&lt;/li&gt;
&lt;li&gt;Allows you to get at every version, including the original, even once destroyed.&lt;/li&gt;
&lt;li&gt;Allows you to get at every version even if the schema has since changed.&lt;/li&gt;
&lt;li&gt;Automatically records who was responsible if your controller has a &lt;code&gt;current_user&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;Allows you to set who is responsible at model-level (useful for migrations).&lt;/li&gt;
&lt;li&gt;Can be turned off/on (useful for migrations).&lt;/li&gt;
&lt;li&gt;No configuration necessary.&lt;/li&gt;
&lt;li&gt;Stores everything in a single database table (generates migration for you).&lt;/li&gt;
&lt;li&gt;Thoroughly tested.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Rails Version&lt;/h2&gt;

&lt;p&gt;Known to work on Rails 2.3.  Probably works on Rails 2.2 and 2.1.&lt;/p&gt;

&lt;h2&gt;Basic Usage&lt;/h2&gt;

&lt;p&gt;PaperTrail is simple to use.  Just add 15 characters to a model to get a paper trail of every &lt;code&gt;create&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, and &lt;code&gt;destroy&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;This gives you a &lt;code&gt;versions&lt;/code&gt; method which returns the paper trail of changes to your model.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
&gt;&gt; widget = Widget.find 42
&gt;&gt; widget.versions             # [&amp;lt;Version&amp;gt;, &amp;lt;Version&amp;gt;, ...]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once you have a version, you can find out what happened:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
&gt;&gt; v = widget.versions.last
&gt;&gt; v.event                     # 'update' (or 'create' or 'destroy')
&gt;&gt; v.whodunnit                 # '153'  (if the update was via a controller and
                               #         the controller has a current_user method,
                               #         here returning the id of the current user)
&gt;&gt; v.created_at                # when the update occurred
&gt;&gt; widget = v.reify            # the widget as it was before the update;
                               # would be nil for a create event
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;PaperTrail stores the pre-change version of the model, unlike some other auditing/versioning plugins, so you can retrieve the original version.  This is useful when you start keeping a paper trail for models that already have records in the database.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
&gt;&gt; widget = Widget.find 153
&gt;&gt; widget.name                                 # 'Doobly'

# Add has_paper_trail to Widget model.

&gt;&gt; widget.versions                             # []
&gt;&gt; widget.update_attributes :name =&gt; 'Wotsit'
&gt;&gt; widget.versions.first.reify.name            # 'Doobly'
&gt;&gt; widget.versions.first.event                 # 'update'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This also means that PaperTrail does not waste space storing a version of the object as it currently stands.  The &lt;code&gt;versions&lt;/code&gt; method gives you previous versions; to get the current one just call a finder on your &lt;code&gt;Widget&lt;/code&gt; model as usual.&lt;/p&gt;

&lt;p&gt;Here&#8217;s a helpful table showing what PaperTrail stores:&lt;/p&gt;

&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;Event&lt;/th&gt;
    &lt;th&gt;Model Before&lt;/th&gt;
    &lt;th&gt;Model After&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;create&lt;/td&gt;
    &lt;td&gt;nil&lt;/td&gt;
    &lt;td&gt;widget&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;update&lt;/td&gt;
    &lt;td&gt;widget&lt;/td&gt;
    &lt;td&gt;widget&#8217;&lt;/td&gt;
  &lt;tr&gt;
    &lt;td&gt;destroy&lt;/td&gt;
    &lt;td&gt;widget&lt;/td&gt;
    &lt;td&gt;nil&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;PaperTrail stores the values in the Model Before column.  Most other auditing/versioning plugins store the After column.&lt;/p&gt;

&lt;h2&gt;Reverting Or Undeleting A Model&lt;/h2&gt;

&lt;p&gt;PaperTrail makes reverting to a previous version easy:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
&gt;&gt; widget = Widget.find 42
&gt;&gt; widget.update_attributes :name =&gt; 'Blah blah'
# Time passes....
&gt;&gt; widget = Widget.find(42).versions.last.reify  # the widget as it was before the update
&gt;&gt; widget.save  # reverted to its previous version
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Undeleting is just as simple:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
&gt;&gt; widget = Widget.find 42
&gt;&gt; widget.destroy
# Time passes....
&gt;&gt; widget = Version.find(153).reify    # the widget as it was before it was destroyed
&gt;&gt; widget.save                         # the widget lives!
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In fact you could use PaperTrail to implement an undo system, though I haven&#8217;t had the opportunity yet to do it myself.&lt;/p&gt;

&lt;h2&gt;Finding Out Who Was Responsible For A Change&lt;/h2&gt;

&lt;p&gt;If your &lt;code&gt;ApplicationController&lt;/code&gt; has a &lt;code&gt;current_user&lt;/code&gt; method, PaperTrail will store the value it returns in the &lt;code&gt;version&lt;/code&gt;&#8217;s &lt;code&gt;whodunnit&lt;/code&gt; column.  Note that this column is a string so you will have to convert it to an integer if it&#8217;s an id and you want to look up the user later on:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
&gt;&gt; last_change = Widget.versions.last
&gt;&gt; user_who_made_the_change = User.find last_change.whodunnit.to_i
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In a migration or in &lt;code&gt;script/console&lt;/code&gt; you can set who is responsible like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
&gt;&gt; PaperTrail.whodunnit = 'Andy Stewart'
&gt;&gt; widget.update_attributes :name =&gt; 'Wibble'
&gt;&gt; widget.versions.last.whodunnit              # Andy Stewart
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Turning PaperTrail Off/On&lt;/h2&gt;

&lt;p&gt;Sometimes you don&#8217;t want to store changes.  Perhaps you are only interested in changes made
by your users and don&#8217;t need to store changes you make yourself in, say, a migration.&lt;/p&gt;

&lt;p&gt;If you are about change some widgets and you don&#8217;t want a paper trail of your changes, you can
turn PaperTrail off like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
&gt;&gt; Widget.paper_trail_off
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And on again like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
&gt;&gt; Widget.paper_trail_on
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Installation&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Install PaperTrail either as a gem or as a plugin:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;config.gem 'airblade-paper_trail', :lib =&gt; 'paper_trail', :source =&gt; 'http://gems.github.com'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;or:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;script/plugin install git://github.com/airblade/paper_trail.git&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generate a migration which will add a &lt;code&gt;versions&lt;/code&gt; table to your database.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;script/generate paper_trail&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run the migration.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rake db:migrate&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add &lt;code&gt;has_paper_trail&lt;/code&gt; to the models you want to track.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Testing&lt;/h2&gt;

&lt;p&gt;PaperTrail has a thorough suite of tests.  However they only run when PaperTrail is sitting in a Rails app&#8217;s &lt;code&gt;vendor/plugins&lt;/code&gt; directory.  If anyone can tell me how to get them to run outside of a Rails app, I&#8217;d love to hear it.&lt;/p&gt;

&lt;h2&gt;Problems&lt;/h2&gt;

&lt;p&gt;Please use GitHub&#8217;s &lt;a href=&quot;http://github.com/airblade/paper_trail/issues&quot;&gt;issue tracker&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Inspirations&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/github/simply_versioned&quot;&gt;Simply Versioned&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://github.com/collectiveidea/acts_as_audited&quot;&gt;Acts As Audited&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Intellectual Property&lt;/h2&gt;

&lt;p&gt;Copyright (c) 2009 Andy Stewart (boss@airbladesoftware.com).
Released under the MIT licence.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2009-06-17:87884</id>
    <published>2009-06-17T09:14:00Z</published>
    <updated>2009-06-17T09:15:15Z</updated>
    <category term="Productivity"/>
    <category term="Quotations"/>
    <link href="http://blog.airbladesoftware.com/2009/6/17/going-back-to-simple" rel="alternate" type="text/html"/>
    <title>Going Back To Simple</title>
<content type="html">
            &lt;blockquote&gt;&lt;div&gt;
&lt;p&gt;Every mistake we’ve made as a company has been because we tried to do too much, not because we didn’t do enough.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;cite&gt;&lt;a href=&quot;http://www.37signals.com/svn/posts/1769-reminder-know-what-youre-measuring&quot;&gt;Jason Fried&lt;/a&gt;, founder of 37signals&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,2009-06-09:87670</id>
    <published>2009-06-09T11:30:00Z</published>
    <updated>2009-06-09T11:32:12Z</updated>
    <category term="Rails"/>
    <link href="http://blog.airbladesoftware.com/2009/6/9/testing-http-digest-authentication-with-shoulda" rel="alternate" type="text/html"/>
    <title>Testing HTTP Digest Authentication With Shoulda</title>
<content type="html">
            &lt;p&gt;I recently started writing a small Rails app where I&#8217;ll be the only administrative user.  (It&#8217;s going to replace Mephisto, which runs this blog and regularly goes rogue on the CPU.)  Anyway, my authentication requirements were simple: log in, log out.  So I asked myself, &#8220;&lt;a href=&quot;http://www.artima.com/intv/simplestP.html&quot;&gt;what&#8217;s the simplest thing that could possibly work&lt;/a&gt;?&#8221;&lt;/p&gt;

&lt;p&gt;Well, &lt;a href=&quot;http://www.ietf.org/rfc/rfc2617.txt&quot;&gt;HTTP authentication&lt;/a&gt; is supposed to be simpler than a form-based approach.  In theory it&#8217;s trivial to code: just copy and paste &lt;a href=&quot;http://github.com/rails/rails/blob/2-3-stable/actionpack/lib/action_controller/http_authentication.rb&quot;&gt;the example from the Rails documentation&lt;/a&gt;.  In practice there were a few catches which took me quite a while to resolve, not least the testing.&lt;/p&gt;

&lt;p&gt;Once I had settled on HTTP authentication I had to choose between basic and digest.  I picked digest because I thought basic and digest would be similarly easy to implement, so I might as well use the securer version.&lt;/p&gt;

&lt;h2&gt;Understanding Rails&#8217; API&lt;/h2&gt;

&lt;p&gt;I hadn&#8217;t implemented HTTP authentication before.  My first problem was finding Rails&#8217; API confusing.  There are three methods:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
  authenticate_or_request_with_http_digest(realm = 'Application', &amp;password_procedure)

  authenticate_with_http_digest(realm = 'Application', &amp;password_procedure)

  request_http_digest_authentication(realm = 'Application', message = nil)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I found them easier to understand in reverse order.&lt;/p&gt;

&lt;p&gt;The last one renders a 401 to the browser, along with headers saying &#8216;use HTTP digest authentication to authenticate&#8217;.  It&#8217;s not actually making a request; it&#8217;s instructing the browser to request the resource again, but this time with the user&#8217;s name and password bundled up as per the HTTP-digest protocol.  The method returns the &lt;code&gt;message&lt;/code&gt;, which defaults to &lt;code&gt;&quot;HTTP Digest: Access denied.\n&quot;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The browser sees the 401 and the &#8216;use HTTP digest authentication&#8217; and pops up a dialog box for the user asking for a name and password.  Once the user has typed these in, the browser sends a new request for the resource, but this time with the user&#8217;s log-in details too.&lt;/p&gt;

&lt;p&gt;The middle one, &lt;code class=&quot;ruby&quot;&gt;authenticate_with_http_digest&lt;/code&gt;, checks whatever name and password the browser supplies to see if they&#8217;re legitimate.  It simply returns &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;.  It doesn&#8217;t know or care whether the browser has just asked the user to type in a name and password, or whether the browser cached whatever legitimate credentials the user typed in previously.&lt;/p&gt;

&lt;p&gt;Now we know what those methods do, we can understand the first one.  It simply wraps them:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
  authenticate_with_http_digest(realm, &amp;password_procedure) ||
  request_http_digest_authentication(realm)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So first it checks whether the user&#8217;s name and password, as sent by the browser, are legitimate.  If the browser had these in a cache, it won&#8217;t have asked the user again.  If the user&#8217;s credentials are good, the method returns &lt;code&gt;true&lt;/code&gt;.  Otherwise — either the browser didn&#8217;t send any credentials or it did but the credentials were bad — we send a 401 to the browser, causing it to ask the user for a name and password, and then to re-request the resource.  In this case the method returns &lt;code&gt;&quot;HTTP Digest: Access denied.\n&quot;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Storing the user in the session&lt;/h2&gt;

&lt;p&gt;Bearing in mind &lt;a href=&quot;http://weblog.rubyonrails.org/2009/6/3/security-problem-with-authenticate_with_http_digest&quot;&gt;a gap in Rails 2.3.2&#8217;s implementation&lt;/a&gt;, we can store the user in the session like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
def authenticate
  result = authenticate_or_request_with_http_digest do |name|
    @user = User.find_by_name(name)
    @user.try(:password) || false
  end
  session[:current_user] = @user.id unless result =~ /denied/
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Log out with HTTP digest&lt;/h2&gt;

&lt;p&gt;Since the browser caches the user&#8217;s name and password, we need a way to force the browser to forget them.  I use a flag which tells my &lt;code&gt;authenticate&lt;/code&gt; method to make the authentication fail:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
class SessionsController &amp;lt; ApplicationController
  def logout
    session[:current_user] = nil       # so the app knows
    session[:logout_requested] = true  # so the browser will know
    redirect_to root_path
  end
end

class ApplicationController &amp;lt; ActionController::Base
  def authenticate
    result = authenticate_or_request_with_http_digest do |name|
      if session[:logout_requested]
        session[:logout_requested] = nil   # reset flag
        false
      else
        @user = User.find_by_name(name)
        @user.try(:password) || false
      end
    end
    session[:current_user] = @user.id unless result =~ /denied/
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I got this idea from &lt;a href=&quot;http://blog.edendevelopment.co.uk/2009/03/23/under-the-hood-not-so-basic-authentication/&quot;&gt;Eden Development&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Alternative implementation&lt;/h2&gt;

&lt;p&gt;Given our triumvirate of HTTP digest authentication methods above, we could rewrite our &lt;code&gt;authenticate&lt;/code&gt; method in terms of the two lower-level methods like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
class ApplicationController &amp;lt; ActionController::Base
  def authenticate
    success = authenticate_with_http_digest do |name|
      if session[:logout_requested]
        session[:logout_requested] = nil   # reset flag
        false
      else
        @user = User.find_by_name(name)
        @user.try(:password) || false
      end
    end

    if success
      session[:current_user] = @user.id
    else
      request_http_digest_authentication
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;The Tests&lt;/h2&gt;

&lt;p&gt;Testing HTTP digest authentication is not easy.  Fortunately &lt;a href=&quot;http://lightyearsoftware.com/blog/2009/04/testing-http-digest-authentication-in-rails/&quot;&gt;Steve Madsen figured it out&lt;/a&gt; .  I incorporated his code into this &lt;a href=&quot;http://thoughtbot.com/projects/shoulda&quot;&gt;Shoulda&lt;/a&gt; macro:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
# test/shoulda_macros/security.rb:

module AirWeb
  module Shoulda

    def should_be_unauthorized(http_method, action, options = {})
      context &quot;on #{http_method} to #{action}&quot; do
        setup do
          options.each{ |k,v| options[k] = instance_eval(v) }
          send http_method, action, options
        end
        should_respond_with :unauthorized
      end
    end

  end
end

module AirWeb
  module Shoulda
    module Helpers

      def log_in
        # Any user will do.
        authenticate_with_http_digest(User.first.name, User.first.password)
        @request.session[:current_user] = User.first.id
        @request.session[:logout_requested ] = false
      end

      def log_out
        @request.session[:current_user] = nil
        @request.session[:logout_requested ] = true
      end

    end
  end
end

ActiveSupport::TestCase.send :include, AirWeb::Shoulda::Helpers
ActiveSupport::TestCase.extend AirWeb::Shoulda

require 'digest/md5'

class ActionController::TestCase
  def authenticate_with_http_digest(user = 'admin', password = 'admin', realm = 'Application')
    unless ActionController::Base &amp;lt; ActionController::ProcessWithTest
      ActionController::Base.class_eval { include ActionController::ProcessWithTest }
    end

    @controller.instance_eval %Q(
      alias real_process_with_test process_with_test

      def process_with_test(request, response)
        credentials = {
          :uri =&gt; request.env['REQUEST_URI'],
          :realm =&gt; &quot;#{realm}&quot;,
          :username =&gt; &quot;#{user}&quot;,
          :nonce =&gt; ActionController::HttpAuthentication::Digest.nonce,
          :opaque =&gt; ActionController::HttpAuthentication::Digest.opaque,
        }
        request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Digest.encode_credentials(
          request.request_method, credentials, &quot;#{password}&quot;, false
        )
        real_process_with_test(request, response)
      end
    )
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This allows me to write test code like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
  context 'The public' do
    setup { log_out }
    should_be_unauthorized :get, :new
    should_be_unauthorized :create, :new
    should_be_unauthorized :update, 'Article.first.id'
  end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It took me a while to realise that &lt;code&gt;Article&lt;/code&gt; is not visible in the &lt;code&gt;context&lt;/code&gt;&#8217;s scope.  You have to pass a string to your custom should method, then &lt;code&gt;instance_eval&lt;/code&gt; it in the &lt;code&gt;setup&lt;/code&gt; block.  (Or you could pass an instance variable.)&lt;/p&gt;

&lt;h2&gt;PUT and DELETE problem with HTTP digest&lt;/h2&gt;

&lt;p&gt;In the course of all this, I realised that my app wouldn&#8217;t allow me to update (via PUT) or destroy (via DELETE).  It turns out &lt;a href=&quot;https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2490-http-digest-auth-uses-wrong-request-method-for-put-delete#ticket-2490-1&quot;&gt;there was a bug&lt;/a&gt; but it has been &lt;a href=&quot;http://github.com/rails/rails/commit/dbb025827992331843566be418a6f86d89f41868&quot;&gt;fixed in commit dbb025&lt;/a&gt; by Steve Madsen.  This is on the 2-3-stable branch but not in the gems, so you&#8217;ll have to &lt;a href=&quot;http://blog.airbladesoftware.com/2009/4/28/how-to-vendor-rails&quot;&gt;vendor Rails&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;I rather wish I had stuck with form-based authentication!  However that&#8217;s because I hadn&#8217;t looked at HTTP authentication before.  Now I have, the next time I come to implement authentication, HTTP authentication actually will be the simplest thing that could work.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2009-06-05:87639</id>
    <published>2009-06-05T17:44:00Z</published>
    <updated>2009-06-06T14:18:47Z</updated>
    <category term="Rails"/>
    <link href="http://blog.airbladesoftware.com/2009/6/5/the-rails-toolbox" rel="alternate" type="text/html"/>
    <title>The Rails Toolbox</title>
<content type="html">
            &lt;h2&gt;The Goal&lt;/h2&gt;

&lt;p&gt;Inspired by &lt;a href=&quot;http://ruby-toolbox.com/&quot;&gt;The Ruby Toolbox&lt;/a&gt;, I wanted to construct a Rails Toolbox.  The Ruby Toolbox mines &lt;a href=&quot;http://github.com&quot;&gt;GitHub&lt;/a&gt;, rating the tools by the number of watchers and forks; how to do something similar for Rails?&lt;/p&gt;

&lt;h2&gt;The Method&lt;/h2&gt;

&lt;p&gt;First of all we need to define what counts as a Rails tool.  I&#8217;m saying plugins and gems.&lt;/p&gt;

&lt;p&gt;Second, we need to find out which plugins and gems people have installed in their Rails apps.  Here we make use of a handy feature introduced in Rails 2.3: &lt;a href=&quot;http://railscasts.com/episodes/148-app-templates-in-rails-2-3&quot;&gt;Rails Application Templates&lt;/a&gt;.  These templates are scripts which let you customise a new Rails application, and crucially they have these three attributes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They specify which plugins to install in the new Rails app.&lt;/li&gt;
&lt;li&gt;They specify which gems to install in the new Rails app.&lt;/li&gt;
&lt;li&gt;People tend to pop them on GitHub even if their apps aren&#8217;t open-source.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So all we need to do is mine GitHub for these templates, hammer through them, and tot up the plugins and gems they use.&lt;/p&gt;

&lt;h2&gt;The Code&lt;/h2&gt;

&lt;p&gt;I wrote some &lt;a href=&quot;http://github.com/airblade/rails-templates/blob/master/rails_toolbox.rb&quot;&gt;code&lt;/a&gt; to do this.  It uses &lt;a href=&quot;http://railstips.org&quot;&gt;John Nunemaker&lt;/a&gt;&#8217;s &lt;a href=&quot;http://github.com/jnunemaker/httparty/tree/master&quot;&gt;HTTParty&lt;/a&gt; to wrap &lt;a href=&quot;http://develop.github.com/&quot;&gt;GitHub&#8217;s API&lt;/a&gt;, or at least the parts I needed.&lt;/p&gt;

&lt;p&gt;This was the first time I&#8217;ve used &lt;a href=&quot;http://github.com/jnunemaker/httparty/tree/master&quot;&gt;HTTParty&lt;/a&gt; and I liked it a lot.  I haven&#8217;t got up and running with someone else&#8217;s code so quickly for ages.  As an aside, I think it&#8217;s supposed to be &#8220;HTTP-party&#8221; but I prefer &#8220;HTTP-arty&#8221;.&lt;/p&gt;

&lt;h2&gt;The Results&lt;/h2&gt;

&lt;p&gt;I would love to build a website for you as shiny as &lt;a href=&quot;http://ruby-toolbox.com/&quot;&gt;The Ruby Toolbox&#8217;s&lt;/a&gt;.  But not quite enough to actually do it.  You&#8217;ll have to settle for two lists.&lt;/p&gt;

&lt;p&gt;There&#8217;s also one small caveat to bear in mind but I&#8217;ll come to that later.&lt;/p&gt;

&lt;h3&gt;Top 33 Gems&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;thoughtbot-factory_girl (6)&lt;/li&gt;
&lt;li&gt;RedCloth (6)&lt;/li&gt;
&lt;li&gt;mislav-will_paginate (5)&lt;/li&gt;
&lt;li&gt;ruby-openid (5)&lt;/li&gt;
&lt;li&gt;thoughtbot-shoulda (5)&lt;/li&gt;
&lt;li&gt;hpricot (3)&lt;/li&gt;
&lt;li&gt;mocha (3)&lt;/li&gt;
&lt;li&gt;haml (2)&lt;/li&gt;
&lt;li&gt;rspec (2)&lt;/li&gt;
&lt;li&gt;rubyist-aasm (2)&lt;/li&gt;
&lt;li&gt;sqlite3-ruby (2)&lt;/li&gt;
&lt;li&gt;rspec-rails (2)&lt;/li&gt;
&lt;li&gt;stefanpenner-my_scaffold (2)&lt;/li&gt;
&lt;li&gt;dm-validations (1)&lt;/li&gt;
&lt;li&gt;sevenwire-attr_encrypted (1)&lt;/li&gt;
&lt;li&gt;datamapper4rail (1)&lt;/li&gt;
&lt;li&gt;dm-timestamps (1)&lt;/li&gt;
&lt;li&gt;mislav-will-paginate (1)&lt;/li&gt;
&lt;li&gt;rcov (1)&lt;/li&gt;
&lt;li&gt;authlogic (1)&lt;/li&gt;
&lt;li&gt;chriseppstein-compass (1)&lt;/li&gt;
&lt;li&gt;addressable (1)&lt;/li&gt;
&lt;li&gt;quietbacktrace (1)&lt;/li&gt;
&lt;li&gt;yfactorial-utility_scopes (1)&lt;/li&gt;
&lt;li&gt;rdiscount (1)&lt;/li&gt;
&lt;li&gt;jchris-couchrest (1)&lt;/li&gt;
&lt;li&gt;bj (1)&lt;/li&gt;
&lt;li&gt;do_sqlite3 (1)&lt;/li&gt;
&lt;li&gt;thoughtbot-quietbacktrace (1)&lt;/li&gt;
&lt;li&gt;sevenwire-forgery (1)&lt;/li&gt;
&lt;li&gt;sevenwire-configatron (1)&lt;/li&gt;
&lt;li&gt;aws-s3 (1)&lt;/li&gt;
&lt;li&gt;faker (1)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Top 40 Plugins&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;rspec (8)&lt;/li&gt;
&lt;li&gt;rspec-rails (8)&lt;/li&gt;
&lt;li&gt;exception_notifier (6)&lt;/li&gt;
&lt;li&gt;open_id_authentication (5)&lt;/li&gt;
&lt;li&gt;restful-authentication (4)&lt;/li&gt;
&lt;li&gt;asset_packager (4)&lt;/li&gt;
&lt;li&gt;role_requirement (3)&lt;/li&gt;
&lt;li&gt;hoptoad_notifier (3)&lt;/li&gt;
&lt;li&gt;acts_as_taggable_redux (3)&lt;/li&gt;
&lt;li&gt;aasm (2)&lt;/li&gt;
&lt;li&gt;active_scaffold (2)&lt;/li&gt;
&lt;li&gt;will_paginate (2)&lt;/li&gt;
&lt;li&gt;squirrel (2)&lt;/li&gt;
&lt;li&gt;cucumber (2)&lt;/li&gt;
&lt;li&gt;year_after_year (1)&lt;/li&gt;
&lt;li&gt;semantic_form_builder (1)&lt;/li&gt;
&lt;li&gt;acl_system2 (1)&lt;/li&gt;
&lt;li&gt;factory_girl (1)&lt;/li&gt;
&lt;li&gt;basic_model (1)&lt;/li&gt;
&lt;li&gt;restful_authentication (1)&lt;/li&gt;
&lt;li&gt;permanent_records (1)&lt;/li&gt;
&lt;li&gt;webrat (1)&lt;/li&gt;
&lt;li&gt;dataset (1)&lt;/li&gt;
&lt;li&gt;make_resourceful (1)&lt;/li&gt;
&lt;li&gt;machinist (1)&lt;/li&gt;
&lt;li&gt;bootstrapper (1)&lt;/li&gt;
&lt;li&gt;ssl_requirement (1)&lt;/li&gt;
&lt;li&gt;authlogic (1)&lt;/li&gt;
&lt;li&gt;mile_marker (1)&lt;/li&gt;
&lt;li&gt;flash-message-conductor (1)&lt;/li&gt;
&lt;li&gt;active_presenter (1)&lt;/li&gt;
&lt;li&gt;shoulda (1)&lt;/li&gt;
&lt;li&gt;quietbacktrace (1)&lt;/li&gt;
&lt;li&gt;forgery (1)&lt;/li&gt;
&lt;li&gt;newrelic_rpm (1)&lt;/li&gt;
&lt;li&gt;limerick_rake (1)&lt;/li&gt;
&lt;li&gt;action_mailer_tls (1)&lt;/li&gt;
&lt;li&gt;facebooker (1)&lt;/li&gt;
&lt;li&gt;in_place_editing (1)&lt;/li&gt;
&lt;li&gt;rr (1)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Caveat&lt;/h3&gt;

&lt;p&gt;These results are based on the first 30 repositories returned by &lt;a href=&quot;http://develop.github.com/&quot;&gt;GitHub&#8217;s API&lt;/a&gt;;  The GUI returns 243 results.  If anyone know hows to get the next 30 (and the 30 after, etc), please let me know in the comments.  Thanks ;)&lt;/p&gt;

&lt;p&gt;Update: this is a &lt;a href=&quot;http://github.com/develop/develop.github.com/issues/labels/feature#issue/1&quot;&gt;known shortcoming&lt;/a&gt;.  There&#8217;s not much we can do until it&#8217;s fixed.&lt;/p&gt;

&lt;h2&gt;Discussion&lt;/h2&gt;

&lt;p&gt;We can&#8217;t reach any statistically significant conclusions about the popularity of Rails plugins and gems: with only 30 repositories out of 243 we do not have a sufficiently powerful sample.  Also none of mine are showing up in the results so the data must be incomplete.&lt;/p&gt;

&lt;p&gt;We can mine all the data we need to build a complete &lt;a href=&quot;http://oreilly.com/catalog/9780596529321/&quot;&gt;recommendation system&lt;/a&gt;.  Rails&#8217; plugin installer and gem-installing Rake task could be beefed up like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
  $ script/plugin install git://github.com/technoweenie/restful-authentication.git
  [...Git stuff...]
  People who installed restful-authentication were also interested in authlogic.
  Would you like to try authlogic instead (y/n)?
  $ y
  Uninstalling restful-authentication...
  Installing authlogic...
  [...Git stuff...]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Of course not all Rails app template creators are going to choose the same plugins and gems as you.  The recommendation system could incorporate some Bayesian mathematics or a neural network to learn your predilections and adapt.  I see a great future for this.  Somebody should get right on it.&lt;/p&gt;

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

&lt;p&gt;The mining method seems sound, though, and the code works.  All we need now is a shiny website!&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2009-06-04:87635</id>
    <published>2009-06-04T12:00:00Z</published>
    <updated>2009-06-04T12:02:04Z</updated>
    <category term="CSS"/>
    <category term="Typography"/>
    <link href="http://blog.airbladesoftware.com/2009/6/4/vertical-baseline-rhythm" rel="alternate" type="text/html"/>
    <title>Vertical Baseline Rhythm</title>
<content type="html">
            &lt;h2&gt;Why bother?&lt;/h2&gt;

&lt;p&gt;I spend my working life creating web apps.  I do everything, but first and foremost I am a programmer.  Although I like to think I have a good eye for web design — how things look — it&#8217;s &#8220;read only&#8221;: I know and appreciate a good design when I see it but I can&#8217;t create it myself.&lt;/p&gt;

&lt;p&gt;Since I&#8217;m hopelessly out of my depth with every image editor on the market, including &lt;a href=&quot;http://www.flyingmeat.com/acorn/&quot;&gt;Acorn&lt;/a&gt; (&#8220;you don&#8217;t need a Ph.D in computer graphics&#8221;), I have been drawn increasingly to &lt;a href=&quot;http://www.aisleone.net/2009/design/8-ways-to-improve-your-typography/&quot;&gt;typography&lt;/a&gt;.  Not in terms of designing typefaces but rather learning how to make text look better.  You tend to use a calculator, not an image editor, so it&#8217;s more tractable for me.&lt;/p&gt;

&lt;p&gt;Anyway, establishing a vertical baseline rhythm is one technique to improve the legibility of text.  After reading &lt;a href=&quot;http://24ways.org/2006/compose-to-a-vertical-rhythm&quot;&gt;Compose to a Vertical Rhythm&lt;/a&gt;, &lt;a href=&quot;http://www.fivesimplesteps.co.uk/&quot;&gt;Designing for the Web&lt;/a&gt;, and &lt;a href=&quot;http://nubyonrails.com/articles/get-rhythm-in-your-baseline&quot;&gt;Get Rhythm in Your Baseline&lt;/a&gt;, I thought I&#8217;d have a go on &lt;a href=&quot;http://girlsinfootball.co.uk&quot;&gt;Girls in Football&lt;/a&gt; (in beta, so unfortunately you can&#8217;t see what I mean yet).&lt;/p&gt;

&lt;h2&gt;Helpful Tools&lt;/h2&gt;

&lt;p&gt;Sorting out the textual elements was straightforward.  Two tools helped greatly: &lt;a href=&quot;http://site.ringce.com/products/slammer/slammer.html&quot;&gt;Slammer&lt;/a&gt; and &lt;a href=&quot;http://www.debugbar.com/&quot;&gt;DebugBar&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://site.ringce.com/products/slammer/slammer.html&quot;&gt;Slammer&lt;/a&gt; is an OS X app that floats a semi-transparent grid over other windows, allowing you to see at a glance whether your baselines are rhythmic.  It does more, but this alone makes it indispensable.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.debugbar.com/&quot;&gt;DebugBar&lt;/a&gt; is an Internet Explorer plugin which comes closer to &lt;a href=&quot;http://getfirebug.com/&quot;&gt;Firebug&lt;/a&gt; than anything else I&#8217;ve seen on IE.  It has a DOM inspector, HTTP inspector, Javascript inspector and console, and more.  I find it extremely useful for getting to the bottom of bizarre IE behaviour.&lt;/p&gt;

&lt;h2&gt;Stumbling Blocks&lt;/h2&gt;

&lt;p&gt;Once the textual elements are done, you are left with forms and images.  Forms elements and buttons throw a spanner in the works because their sizes vary from browser to browser.  Images disrupt the baseline rhythm unless their heights are an exact multiple of your line spacing — which generally they aren&#8217;t.&lt;/p&gt;

&lt;p&gt;I haven&#8217;t tackled forms yet, but I did solve the image problem.&lt;/p&gt;

&lt;h2&gt;jQuery Plugin for Images&lt;/h2&gt;

&lt;p&gt;Geoffrey Grosenback &lt;a href=&quot;http://nubyonrails.com/articles/get-rhythm-in-your-baseline&quot;&gt;mentioned&lt;/a&gt; a technique he had heard about for handling images: replace each image with a div of the same width and a height which is a multiple of the baseline rhythm, and set the image as the div&#8217;s background.  Since the image is now in the background it won&#8217;t overflow the div and will therefore slot neatly into the baselines.&lt;/p&gt;

&lt;p&gt;This avoids squashing the image, though it does mean chopping a little off if you round the height down to the nearest baseline.&lt;/p&gt;

&lt;p&gt;Anyway, I made this into a &lt;a href=&quot;http://github.com/airblade/jquery-rhythm/tree/master&quot;&gt;jQuery plugin called rhythm&lt;/a&gt; which can be used like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;
  $(window).load(function() {
    $('img').rhythm();
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It works in Safari, Firefox and IE7.&lt;/p&gt;

&lt;p&gt;You can see it in action on &lt;a href=&quot;http://girlsinfootball.co.uk&quot;&gt;Girls in Football&lt;/a&gt;, or at least you will be able to when we come out of beta.  For every image it calculates where the nearest baseline is and &#8220;rounds the image&#8221; up or down to it.  When rounding down you lose a little bit of image, and when rounding up you gain a little whitespace.&lt;/p&gt;

&lt;p&gt;It works really well, and it&#8217;s very satisfying to drop &lt;a href=&quot;http://site.ringce.com/products/slammer/slammer.html&quot;&gt;Slammer&lt;/a&gt; over the bottom of your page and find the vertical baseline rhythm still going strongly.&lt;/p&gt;

&lt;p&gt;Now I need to apply everything I&#8217;ve learned to this site&#8230;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2009-05-27:87412</id>
    <published>2009-05-27T15:12:00Z</published>
    <updated>2009-05-27T15:13:33Z</updated>
    <category term="Quotations"/>
    <link href="http://blog.airbladesoftware.com/2009/5/27/managing-expectations" rel="alternate" type="text/html"/>
    <title>Managing Expectations</title>
<content type="html">
            &lt;blockquote&gt;&lt;div&gt;
&lt;p&gt;The GUI is very limited, and I’m not really motivated to address that, or to give users the features they’re asking for. Similarly, I don’t take bug reports very seriously.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;cite&gt;&lt;a href=&quot;http://po-ru.com/diary/thoughts-on-the-future-of-the-iplayer-downloader/&quot;&gt;Paul Battley keeps it real&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,2009-05-23:87287</id>
    <published>2009-05-23T20:00:00Z</published>
    <updated>2009-05-23T20:00:41Z</updated>
    <category term="Databases"/>
    <category term="Rails"/>
    <link href="http://blog.airbladesoftware.com/2009/5/23/a-better-way-to-import-legacy-data-in-rails" rel="alternate" type="text/html"/>
    <title>A Better Way To Import Legacy Data In Rails</title>
<content type="html">
            &lt;p&gt;Do you have to run a Rails app alongside the legacy app it&#8217;s replacing?  The legacy app remains the authority for some data, such as users, while the Rails app is the authority for other data.&lt;/p&gt;

&lt;p&gt;I&#8217;m in this situation on one project.  My Rails app is replacing a Mambo CMS piece by piece.  Once the Mambo app is fully replaced the Rails app will be the authority for all data in the system.  Until then, the Rails app must keep itself synchronised with the Mambo app&#8217;s data for those models where the Mambo app remains the authority.&lt;/p&gt;

&lt;p&gt;In my Rails app eight models&#8217; data must be imported from five legacy tables.  Other models refer to those eight models so I need to maintain referential integrity.&lt;/p&gt;

&lt;h2&gt;Acts As Importable&lt;/h2&gt;

&lt;p&gt;My first effort at writing the import code was alright.  It worked.  Recently, though, I came across &lt;a href=&quot;http://openmonkey.com/about&quot;&gt;Tim Riley&lt;/a&gt;&#8217;s excellent &lt;a href=&quot;http://github.com/timriley/acts-as-importable/tree/master&quot;&gt;acts_as_importable plugin&lt;/a&gt; and this has made all the difference.  Before his plugin my code was a little ugly and its intent was obscure.  Now, using his plugin, my code is clean, clear, and trivial to maintain.&lt;/p&gt;

&lt;p&gt;Tim wrote a &lt;a href=&quot;http://openmonkey.com/articles/2009/05/importing-legacy-data-in-rails&quot;&gt;clear article explaining how to import legacy data into Rails&lt;/a&gt;.  Two of his design decisions stood out for me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The legacy models know how to turn themselves into non-legacy models, not vice-versa.&lt;/li&gt;
&lt;li&gt;The legacy models don&#8217;t export themselves; a dedicated class has that responsibility.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I made three additions to Tim&#8217;s recipe.&lt;/p&gt;

&lt;p&gt;First I made my legacy models read-only, using &lt;a href=&quot;http://onehackoranother.com/&quot;&gt;Jason Frame&lt;/a&gt;&#8217;s &lt;a href=&quot;http://github.com/jaz303/read_only_model/tree/master&quot;&gt;read_only_model plugin&lt;/a&gt;, just to be on the safe side.  My client would be displeased if I accidentally wrote over any of his data.&lt;/p&gt;

&lt;p&gt;Second I turned off &lt;a href=&quot;http://freelancing-god.github.com/ts/en/deltas.html&quot;&gt;Thinking Sphinx&#8217;s delta indexing&lt;/a&gt; before importing any data, turning it on again afterwards and re-indexing.  Leaving the delta indexing on during the import would be a waste of resources and would significantly slow down the import.&lt;/p&gt;

&lt;p&gt;Third I turned off auditing (using the &lt;a href=&quot;http://github.com/collectiveidea/acts_as_audited/tree/master&quot;&gt;acts_as_audited plugin&lt;/a&gt;) during the import process for a similar reason.  The audit trail of who updated which record would become next to useless if swamped with tens of thousands of entries each night.&lt;/p&gt;

&lt;p&gt;So my importer looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
class Legacy::Importer
  def self.run
   disable_auditing
   disable_delta_indexing

   # The import (see Tim Riley's article)
   # ...

  ensure
    enable_auditing
    enable_delta_indexing
  end

  private

  def self.disable_delta_indexing
    ThinkingSphinx.deltas_enabled = false
  end

  def self.enable_delta_indexing
    ThinkingSphinx.deltas_enabled = true
  end

  @@audited_models = [ Member, Report ] # etc

  def self.disable_auditing
    @@audited_models.each { |m| m.disable_auditing }
  end

  def self.enable_auditing
    @@audited_models.each { |m| m.enable_auditing }
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Anyway, if you are in the same boat you should try out &lt;a href=&quot;http://github.com/timriley/acts-as-importable/tree/master&quot;&gt;acts_as_importable&lt;/a&gt;.  It certainly improved my import process.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2009-05-20:87154</id>
    <published>2009-05-20T08:11:00Z</published>
    <updated>2009-05-20T08:14:46Z</updated>
    <category term="Quotations"/>
    <category term="Rails"/>
    <link href="http://blog.airbladesoftware.com/2009/5/20/iceberg-development" rel="alternate" type="text/html"/>
    <title>Iceberg Development</title>
<content type="html">
            &lt;blockquote&gt;&lt;div&gt;
&lt;p&gt;What I find personally frustrating is that for a lot of the most interesting projects, the hard work is the first 98%, after which there’s nothing “cool” to show. The final 2%, which is usually a day or two of work, produces the whiz-bang demos.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;cite&gt;&lt;a href=&quot;http://yehudakatz.com/2009/05/08/railsconf-wrapup/&quot;&gt;Yehuda Katz&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,2009-04-28:86360</id>
    <published>2009-04-28T13:29:00Z</published>
    <updated>2009-05-08T10:11:21Z</updated>
    <category term="Deployment"/>
    <category term="Rails"/>
    <link href="http://blog.airbladesoftware.com/2009/4/28/how-to-vendor-rails" rel="alternate" type="text/html"/>
    <title>How To Vendor Rails</title>
<content type="html">
            &lt;p&gt;Today I was bitten by the &lt;a href=&quot;http://code.google.com/p/phusion-passenger/issues/detail?id=279&quot;&gt;incompatibility of Rack 1.0.0, Passenger 2.2.1, and Rails 2.3.2.1&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;  &lt;code&gt;undefined method `new' for &quot;Rack::Lock&quot;:String (NoMethodError)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Since I had already (inadvertently) upgraded Rack, the solution was to upgrade both Passenger and Rails.&lt;/p&gt;

&lt;p&gt;Upgrading &lt;a href=&quot;http://blog.phusion.nl/2009/04/26/phusion-passenger-222-released/&quot;&gt;Passenger to 2.2.2&lt;/a&gt; was straightforward.  Just remember to update the paths in your &lt;code&gt;passenger.conf&lt;/code&gt; to point to the 2.2.2 version.&lt;/p&gt;

&lt;p&gt;Upgrading Rails wasn&#8217;t quite as straightforward because the compatibility fixes aren&#8217;t yet available in the Rails gem.  Instead we have to run our application against the latest stable branch, &lt;a href=&quot;http://github.com/rails/rails/commits/2-3-stable&quot;&gt;2-3-stable&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To do this I vendored Rails as a &lt;a href=&quot;http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html&quot;&gt;Git submodule&lt;/a&gt;.  This is nothing new but it&#8217;s the first time I&#8217;ve needed to do it.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
$ git submodule add git://github.com/rails/rails.git vendor/rails
$ git commit -m &quot;Vendored Rails edge as a submodule.&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This got me running on edge Rails.  To run on the 2-3-stable branch I then did:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
$ cd vendor/rails/
$ git checkout origin/2-3-stable
$ cd ../..
$ git add vendor/rails
$ git commit -m &quot;Pinned Rails to branch 2-3-stable as of 4b68deb.&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;http://woss.name/2008/04/11/using-git-submodules-to-track-vendorrails-2/&quot;&gt;Graeme Mathieson&lt;/a&gt;, &lt;a href=&quot;http://ariejan.net/2009/01/04/how-to-start-a-rails-edge-app-the-easy-way/&quot;&gt;Ariejan de Vroom&lt;/a&gt;, &lt;a href=&quot;http://daniel.collectiveidea.com/blog/2008/4/12/git-submodules-part-2&quot;&gt;Daniel Morrison&lt;/a&gt; and &lt;a href=&quot;http://stuff.lilleaas.net/git_submodules&quot;&gt;August Lilleaas&lt;/a&gt; for their helpful articles.&lt;/p&gt;

&lt;p&gt;Locally this all worked fine but on deployment the &lt;code&gt;vendor/rails&lt;/code&gt; directory wasn&#8217;t populated due to the way submodules work.  You have to initialise and update them each time; happily &lt;a href=&quot;http://github.com/jamis/capistrano/commit/598efced2594b20f9056db98f374b77466dcb8e2&quot;&gt;Capistrano supports this&lt;/a&gt; with:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;ruby&quot;&gt;set :git_enable_submodules, true&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;At this stage it&#8217;s a good idea to use a remote cache:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;ruby&quot;&gt;set :deploy_via, :remote_cache&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As and when I go back to running Rails from gems, I&#8217;ll remove references to the submodule in &lt;code&gt;.gitmodules&lt;/code&gt; and &lt;code&gt;.git/config&lt;/code&gt;, and then do:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ git rm --cached vendor/rails&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;http://pitupepito.homelinux.org/?p=24&quot;&gt;Jose Cedeno&lt;/a&gt; via &lt;a href=&quot;http://github.com/guides/using-git-submodules-to-track-plugins&quot;&gt;GitHub Guides&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally my application ran again and I could return to working on it rather than the infrastructure&#8230;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2009-04-10:85682</id>
    <published>2009-04-10T16:35:00Z</published>
    <updated>2009-04-10T16:37:09Z</updated>
    <category term="Deployment"/>
    <category term="Rails"/>
    <category term="Ruby"/>
    <link href="http://blog.airbladesoftware.com/2009/4/10/avoid-typing-rails_env-all-the-time" rel="alternate" type="text/html"/>
    <title>Avoid Typing RAILS_ENV All The Time</title>
<content type="html">
            &lt;p&gt;I often log into my staging or production servers to run a Rake task or fire up the Rails console.  I got fed up long ago with specifying the environment in every command.  For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
$ rake --trace db:migrate:redo RAILS_ENV=production
$ script/console production
$ rake ts:in RAILS_ENV=production
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It just occurred to me to set the environment variable in, er, the environment (&lt;code&gt;~/.bashrc&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
export RAILS_ENV=production
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now I can log in and type simply what I want to type:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
$ rake --trace db:migrate:redo
$ script/console
$ rake ts:in
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I am so embarrassed that I didn&#8217;t think of this three years ago.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2009-04-10:85678</id>
    <published>2009-04-10T14:34:00Z</published>
    <updated>2009-04-14T11:01:22Z</updated>
    <category term="Databases"/>
    <category term="Rails"/>
    <link href="http://blog.airbladesoftware.com/2009/4/10/thinking-sphinx-and-declarative-authorisation" rel="alternate" type="text/html"/>
    <title>Thinking Sphinx and (Declarative) Authorisation</title>
<content type="html">
            &lt;p&gt;&lt;a href=&quot;http://ts.freelancing-gods.com/&quot;&gt;Thinking Sphinx&lt;/a&gt; makes it wonderfully easy to search across multiple models:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
ThinkingSphinx::Search.search 'Your query'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But what happens if your user is only allowed to see some of the data?  On my current project, a signed-in user may see everything but a public user may only see part of the site.  I need to restrict the search to what the user is allowed to see.&lt;/p&gt;

&lt;p&gt;Fortunately what the user is allowed to see, in this case, depends on the class.  For example a public user can see all news stories but no members&#8217; profiles.  It would be harder were a public user allowed to see only some news stories or only some members&#8217; profiles.&lt;/p&gt;

&lt;h2&gt;First Solution&lt;/h2&gt;

&lt;p&gt;My first solution was to restrict the classes which Thinking Sphinx searches, using the handy &lt;code class=&quot;ruby&quot;&gt;:classes&lt;/code&gt; option:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
class SearchController &amp;lt; ApplicationController

  def search
    if params[:q].blank?
      @results = []
    else
      @results = ThinkingSphinx::Search.search \
        params[:q],
        :page    =&gt; params[:page] || 1,
        :classes =&gt; authorised_classes
    end
  end

  private

  def authorised_classes
    [Forum, Member, Post, Review, Story, Team, Topic].select do |klass|
      permitted_to? :read, klass.to_s.tableize.to_sym
    end
  end

end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The array of classes holds all the classes with indexes.  (In reality my app has twice as many but I omitted some for legibility.)&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;ruby&quot;&gt;permitted_to?&lt;/code&gt; method comes from &lt;a href=&quot;http://steffenbartsch.com/blog/&quot;&gt;Steffen Bartsch&lt;/a&gt;&#8217;s excellent &lt;a href=&quot;http://github.com/stffn/declarative_authorization/tree/master&quot;&gt;declarative_authorization&lt;/a&gt; plugin.  There are many different ways to handle authorisation but this is my favourite.  It has elegantly solved every authorisation requirement I have ever had; it just feels right.&lt;/p&gt;

&lt;p&gt;As an aside, the authorisation rules are declared in &lt;code&gt;config/authorization_rules.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
authorization do
  role :guest do
    has_permission_on :forums,  :to =&gt; :read
    has_permission_on :posts,   :to =&gt; :read
    # etc
  end

  role :member do
    has_permission_on :forums,  :to =&gt; :read
    has_permission_on :members, :to =&gt; :read
    has_permission_on :posts,   :to =&gt; :read
    # etc
  end
end

privileges do
  privilege :manage, :includes =&gt; [:create, :read, :update, :delete]
  privilege :read,   :includes =&gt; [:index, :show, :search]
  privilege :create, :includes =&gt; :new
  privilege :update, :includes =&gt; :edit
  privilege :delete, :includes =&gt; :destroy
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can see that a guest may search forums and posts, but not members; a member can search all of them.&lt;/p&gt;

&lt;h2&gt;Second Solution&lt;/h2&gt;

&lt;p&gt;My search controller&#8217;s &lt;code class=&quot;ruby&quot;&gt;authorised_classes&lt;/code&gt; method worked perfectly, but I knew I was setting myself up for a fall in a few months&#8217; time: as and when I added a new class to the domain, I would probably forget to add it to this array of indexed classes.&lt;/p&gt;

&lt;p&gt;Of course Thinking Sphinx knows which of my classes have indexes, so we can leave it to Thinking Sphinx:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
def authorised_classes
  ThinkingSphinx::indexed_models.select do |model|
    permitted_to? :read, model.tableize.to_sym
  end.map { |model| model.classify.constantize }
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I think this is a pretty elegant way to integrate search and authorisation.  Thanks to &lt;a href=&quot;http://freelancing-gods.com/&quot;&gt;Pat Allan&lt;/a&gt; and &lt;a href=&quot;http://steffenbartsch.com/blog/&quot;&gt;Steffen Bartsch&lt;/a&gt; for writing high quality library code that makes my application code much easier to produce!&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2009-04-10:85674</id>
    <published>2009-04-10T13:14:00Z</published>
    <updated>2009-04-10T13:15:29Z</updated>
    <category term="Databases"/>
    <category term="Deployment"/>
    <category term="Rails"/>
    <link href="http://blog.airbladesoftware.com/2009/4/10/deploying-thinking-sphinx" rel="alternate" type="text/html"/>
    <title>Deploying Thinking Sphinx</title>
<content type="html">
            &lt;p&gt;This is how I like to deploy &lt;a href=&quot;http://ts.freelancing-gods.com/&quot;&gt;Thinking Sphinx&lt;/a&gt;.  In summary:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install &lt;a href=&quot;http://www.sphinxsearch.com/&quot;&gt;Sphinx&lt;/a&gt; on the server.&lt;/li&gt;
&lt;li&gt;Decide where you want Sphinx&#8217;s PID file and indexes in production.&lt;/li&gt;
&lt;li&gt;Ignore Sphinx&#8217;s configuration and indexes in development.&lt;/li&gt;
&lt;li&gt;Configure &lt;a href=&quot;http://www.capify.org/&quot;&gt;Capistrano&lt;/a&gt; to work with Thinking Sphinx.&lt;/li&gt;
&lt;li&gt;Set up cron on the server to re-index your data regularly.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Instructions&lt;/h2&gt;

&lt;h3&gt;1.  Install Sphinx on the server.&lt;/h3&gt;

&lt;p&gt;On server:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
$ curl -O http://www.sphinxsearch.com/downloads/sphinx-0.9.8.1.tar.gz
$ gzip -d sphinx-0.9.8.1.tar.gz 
$ tar xvf sphinx-0.9.8.1.tar 
$ cd sphinx-0.9.8.1
$ ./configure
$ make
$ sudo make install
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And to make sure it installed correctly:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
$ search

Sphinx 0.9.8.1-release (r1533)
Copyright (c) 2001-2008, Andrew Aksyonoff

Usage: search [OPTIONS] &amp;lt;word1&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;2.  Decide where you want Sphinx&#8217;s PID file and indexes in production.&lt;/h3&gt;

&lt;p&gt;I like all my PID files in &lt;code&gt;/var/run/&amp;lt;process&amp;gt;&lt;/code&gt;.  We also want to preserve Sphinx&#8217;s indexes across deployments.&lt;/p&gt;

&lt;p&gt;In your app create &lt;code&gt;config/sphinx.yml&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
production:
  pid_file: /var/run/sphinx/searchd.pid
  searchd_files: /path/to/your/app/shared/db/sphinx
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On server:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;pre&gt;
$ sudo mkdir /var/run/sphinx
$ sudo chown deploy:deploy /var/run/sphinx
$ mkdir -p /path/to/your/app/shared/db/sphinx
&lt;/pre&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Adjust the ownership to suit your needs.&lt;/p&gt;

&lt;h3&gt;3.  Ignore Sphinx&#8217;s configuration and indexes in development.&lt;/h3&gt;

&lt;p&gt;This isn&#8217;t really a deployment step but it needs to be done.&lt;/p&gt;

&lt;p&gt;Add to &lt;code&gt;.gitignore&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
config/development/sphinx.conf
db/sphinx/*
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;4.  Configure Capistrano to work with Thinking Sphinx.&lt;/h3&gt;

&lt;p&gt;Add this to your &lt;code&gt;config/deploy.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
# Thinking Sphinx
namespace :thinking_sphinx do
  task :configure, :roles =&gt; [:app] do
    run &quot;cd #{current_path}; rake thinking_sphinx:configure RAILS_ENV=#{rails_env}&quot;
  end
  task :index, :roles =&gt; [:app] do
    run &quot;cd #{current_path}; rake thinking_sphinx:index RAILS_ENV=#{rails_env}&quot;
  end
  task :start, :roles =&gt; [:app] do
    run &quot;cd #{current_path}; rake thinking_sphinx:start RAILS_ENV=#{rails_env}&quot;
  end
  task :stop, :roles =&gt; [:app] do
    run &quot;cd #{current_path}; rake thinking_sphinx:stop RAILS_ENV=#{rails_env}&quot;
  end
  task :restart, :roles =&gt; [:app] do
    run &quot;cd #{current_path}; rake thinking_sphinx:restart RAILS_ENV=#{rails_env}&quot;
  end
end

# Thinking Sphinx typing shortcuts
namespace :ts do
  task :configure, :roles =&gt; [:app] do
    run &quot;cd #{current_path}; rake thinking_sphinx:configure RAILS_ENV=#{rails_env}&quot;
  end
  task :in, :roles =&gt; [:app] do
    run &quot;cd #{current_path}; rake thinking_sphinx:index RAILS_ENV=#{rails_env}&quot;
  end
  task :start, :roles =&gt; [:app] do
    run &quot;cd #{current_path}; rake thinking_sphinx:start RAILS_ENV=#{rails_env}&quot;
  end
  task :stop, :roles =&gt; [:app] do
    run &quot;cd #{current_path}; rake thinking_sphinx:stop RAILS_ENV=#{rails_env}&quot;
  end
  task :restart, :roles =&gt; [:app] do
    run &quot;cd #{current_path}; rake thinking_sphinx:restart RAILS_ENV=#{rails_env}&quot;
  end
end

# http://github.com/jamis/capistrano/blob/master/lib/capistrano/recipes/deploy.rb
# :default -&gt; update, restart
# :update  -&gt; update_code, symlink
namespace :deploy do
  task :before_update do
    # Stop Thinking Sphinx before the update so it finds its configuration file.
    thinking_sphinx.stop
  end

  task :after_update do
    symlink_sphinx_indexes
    thinking_sphinx.configure
    thinking_sphinx.start
  end

  desc &quot;Link up Sphinx's indexes.&quot;
  task :symlink_sphinx_indexes, :roles =&gt; [:app] do
    run &quot;ln -nfs #{shared_path}/db/sphinx #{current_path}/db/sphinx&quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;5.  Set up cron on the server to re-index your data regularly.&lt;/h3&gt;

&lt;p&gt;Edit your cron table (&lt;code&gt;crontab -e&lt;/code&gt;) and add something along the lines of:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
0 * * * * cd /path/to/your/app/current &amp;&amp; /usr/local/bin/rake RAILS_ENV=production thinking_sphinx:index &gt;&gt; /path/to/your/app/current/log/cron.log 2&gt;&amp;1
&lt;/code&gt;&lt;/pre&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2009-03-28:85091</id>
    <published>2009-03-28T16:04:00Z</published>
    <updated>2009-03-28T16:05:09Z</updated>
    <category term="Quotations"/>
    <link href="http://blog.airbladesoftware.com/2009/3/28/long-live-the-individual-useful-resource" rel="alternate" type="text/html"/>
    <title>Long live the individual useful resource</title>
<content type="html">
            &lt;blockquote&gt;&lt;div&gt;
&lt;p&gt;I don’t think most people realize how little site navigation matters anymore. Your site’s navigation is google, topic sites, blogs, and feeds. The “website” is dead. Long live the individual useful resource.&lt;/p&gt;
&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;cite&gt;&lt;a href=&quot;http://tomayko.com/linkings/&quot;&gt;Ryan Tomayko&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,2009-03-21:84846</id>
    <published>2009-03-21T12:45:00Z</published>
    <updated>2009-03-21T12:45:23Z</updated>
    <category term="Notes To Self"/>
    <category term="Rails"/>
    <link href="http://blog.airbladesoftware.com/2009/3/21/note-to-self-links-in-atom-feeds" rel="alternate" type="text/html"/>
    <title>Note to self: links in Atom feeds</title>
<content type="html">
            &lt;p&gt;There are two ways to refer to a resource in an &lt;a href=&quot;http://www.atomenabled.org/developers/syndication/#whatIsAtom&quot;&gt;Atom feed&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you are in a &lt;a href=&quot;http://www.atomenabled.org/developers/syndication/#person&quot;&gt;Person construct&lt;/a&gt;, use the &lt;code&gt;&amp;lt;uri/&amp;gt;&lt;/code&gt; element.&lt;/li&gt;
&lt;li&gt;Everywhere else, use the &lt;a href=&quot;http://www.atomenabled.org/developers/syndication/#link&quot;&gt;Link construct&lt;/a&gt;&#8217;s &lt;code&gt;&amp;lt;link/&amp;gt;&lt;/code&gt; element.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So for example if you are using Rails&#8217; &lt;a href=&quot;http://api.rubyonrails.org/classes/ActionView/Helpers/AtomFeedHelper.html#M001583&quot;&gt;&lt;code&gt;atom_feed&lt;/code&gt; helper&lt;/a&gt;, &lt;code&gt;author&lt;/code&gt; blocks should look like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;
  entry.author do |author|
    author.name 'Andy Stewart'
    author.uri 'http://airbladesoftware.com'
  end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The helper will generate &lt;code&gt;&amp;lt;link/&amp;gt;&lt;/code&gt; elements whenever you use the &lt;code&gt;:url&lt;/code&gt; or &lt;code&gt;:root_url&lt;/code&gt; options.&lt;/p&gt;

&lt;p&gt;You can validate your Atom feeds with the &lt;a href=&quot;http://feedvalidator.org/&quot;&gt;Feed Validator&lt;/a&gt;.  Your feed needs to be publicly available to use the web version of the validator.  Alternatively you can &lt;a href=&quot;http://feedvalidator.org/about.html#where&quot;&gt;run the validator locally&lt;/a&gt; if you have Python.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://blog.airbladesoftware.com/">
    <author>
      <name>Andy Stewart</name>
    </author>
    <id>tag:blog.airbladesoftware.com,2009-02-26:83874</id>
    <published>2009-02-26T11:29:00Z</published>
    <updated>2009-02-26T11:30:11Z</updated>
    <category term="Climate Change"/>
    <category term="Quotations"/>
    <link href="http://blog.airbladesoftware.com/2009/2/26/the-economics-of-renewable-energy" rel="alternate" type="text/html"/>
    <title>The Economics of Renewable Energy</title>
<content type="html">
            &lt;div class=&quot;imagery&quot;&gt;
&lt;img src=&quot;/assets/2009/1/30/broers.jpg&quot; alt=&quot;Lord Broers&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;&#8220;Rather than spending the majority of our time — let alone the mind-numbing sums of taxpayers&#8217; money which make every sum mentioned in this report seem trivial — on propping up our ill-managed banks, we should rapidly launch some infrastructure projects that will secure the nation&#8217;s future. There are renewable energy projects of all sizes that would be appropriate, and future generations would thank us for pursuing them, rather than wondering with dismay how we stumbled into blackouts and failed to meet our goals for reducing carbon dioxide.&#8221;&lt;/p&gt;

&lt;p&gt;&lt;cite&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Alec_Broers,_Baron_Broers&quot;&gt;Lord Broers&lt;/a&gt;, House of Lords &lt;a href=&quot;http://www.theyworkforyou.com/lords/?id=2009-02-24a.142.2&amp;amp;s=speaker%3A13054#g149.0&quot;&gt;motion to take note of the Report&lt;/a&gt; of the &lt;a href=&quot;http://www.parliament.uk/parliamentary_committees/lords_economic_affairs.cfm&quot;&gt;Economic Affairs Committee&lt;/a&gt; on &lt;a href=&quot;http://www.publications.parliament.uk/pa/ld200708/ldselect/ldeconaf/195/19502.htm&quot;&gt;The Economics of Renewable Energy&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
          </content>  </entry>
</feed>
