<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Dave Schweisguth in a Bottle</title>
	<atom:link href="http://daveinabottle.schweisguth.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://daveinabottle.schweisguth.org</link>
	<description>How many meanings of that can you think of?</description>
	<lastBuildDate>Tue, 13 Sep 2011 04:05:25 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='daveinabottle.schweisguth.org' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://0.gravatar.com/blavatar/ac120e7d5d0923b5d0d166d6e123f0f9?s=96&#038;d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>Dave Schweisguth in a Bottle</title>
		<link>http://daveinabottle.schweisguth.org</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://daveinabottle.schweisguth.org/osd.xml" title="Dave Schweisguth in a Bottle" />
	<atom:link rel='hub' href='http://daveinabottle.schweisguth.org/?pushpress=hub'/>
		<item>
		<title>Scattered sightings</title>
		<link>http://daveinabottle.schweisguth.org/2011/09/12/scattered-sightings/</link>
		<comments>http://daveinabottle.schweisguth.org/2011/09/12/scattered-sightings/#comments</comments>
		<pubDate>Tue, 13 Sep 2011 04:05:25 +0000</pubDate>
		<dc:creator>dschweisguth</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://daveinabottle.schweisguth.org/?p=380</guid>
		<description><![CDATA[While waiting for another message in a bottle to drift your way from this blog, you might want to check out Behind the Fan Door, where Fandor&#8216;s engineering team &#8212; of which I am one &#8212; relates our experiences with Ruby and Rails and other things while bringing you fine independent and international films on [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=380&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>While waiting for another message in a bottle to drift your way from this blog, you might want to check out <a href="http://behindthefandoor.wordpress.com/" target="_blank">Behind the Fan Door</a>, where <a href="http://www.fandor.com/">Fandor</a>&#8216;s engineering team &#8212; of which I am one &#8212; relates our experiences with Ruby and Rails and other things while bringing you fine independent and international films on line.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/daveinabottle.wordpress.com/380/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/daveinabottle.wordpress.com/380/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/daveinabottle.wordpress.com/380/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/daveinabottle.wordpress.com/380/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/daveinabottle.wordpress.com/380/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/daveinabottle.wordpress.com/380/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/daveinabottle.wordpress.com/380/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/daveinabottle.wordpress.com/380/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/daveinabottle.wordpress.com/380/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/daveinabottle.wordpress.com/380/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/daveinabottle.wordpress.com/380/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/daveinabottle.wordpress.com/380/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/daveinabottle.wordpress.com/380/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/daveinabottle.wordpress.com/380/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=380&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://daveinabottle.schweisguth.org/2011/09/12/scattered-sightings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/48891dab622b535f3c2b4ec1c8765bed?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">dschweisguth</media:title>
		</media:content>
	</item>
		<item>
		<title>Essential reading for the modern programmer</title>
		<link>http://daveinabottle.schweisguth.org/2011/07/16/essential-reading-for-the-modern-programmer/</link>
		<comments>http://daveinabottle.schweisguth.org/2011/07/16/essential-reading-for-the-modern-programmer/#comments</comments>
		<pubDate>Sun, 17 Jul 2011 07:04:33 +0000</pubDate>
		<dc:creator>dschweisguth</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://daveinabottle.schweisguth.org/?p=364</guid>
		<description><![CDATA[Software is a uniquely plastic medium, and the practice of software development changes constantly and quickly. All software engineers are self-taught; even the college-trained learn most of their trade on the job. Though we learn by doing and by watching others and studying their work, I&#8217;ve found that reading has consistently been the most powerful [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=364&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Software is a uniquely plastic medium, and the practice of software development changes constantly and quickly. All software engineers are self-taught; even the college-trained learn most of their trade on the job. Though we learn by doing and by watching others and studying their work, I&#8217;ve found that reading has consistently been the most powerful way I can understand what I&#8217;m doing and learn new methods. So I&#8217;m constantly recommending to colleagues one book or another, hoping that they&#8217;ll get from it the same value that I did.</p>
<p>To make that easier, here&#8217;s a list I&#8217;ve been meaning to put together for a long time, of books and other writings that have been essential in shaping my practice of programming. Well-read programmers will find few surprises here, but can be sure that any of these that they&#8217;ve missed will be worth their time.</p>
<p><span id="more-364"></span></p>
<p><a href="http://www.amazon.com/Extreme-Programming-Explained-Embrace-Change/dp/0201616416">Extreme Programming Explained, Kent Beck, 1999.</a> (Although there&#8217;s a second edition, I&#8217;ve only read the first.) It&#8217;s only 1999 and nearly all of the essentials of agile development are already here: developer testing, refactoring, pairing, collective ownership, iterations. Twelve years later, it&#8217;s still hard to do much better. This may be the ideal first book for a professional programmer. For extra credit, <a href="http://c2.com/cgi/wiki">the C2 wiki</a>, where I first saw much of this material, is still a great place to see how some of XP&#8217;s ideas matured in public.</p>
<p><a href="http://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530/">Test-Driven Development By Example, Kent Beck, 2003.</a> This book supplies the single magic ingredient missing from <span style="text-decoration:underline;">Extreme Programming Explained</span>, the driving force at the heart of agile development. In a mere 200 pages this book will bring you out of the desert of test-last in which you&#8217;ve been wandering and put you on the path to constant upward productivity. Sound cultish? Yes, it&#8217;s that essential. <a href="http://www.amazon.com/RSpec-Book-Behaviour-Development-Cucumber/dp/1934356379/">The RSpec Book (Chelimsky et al, 2010)</a> covers similar ground but is muddled by details of tool use and the complex relation between unit and functional testing; read it if you write Ruby, but read Beck first.</p>
<p><a href="http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672/">Refactoring, Martin Fowler et al., 1999.</a> The first programming book that made me realize that there was such a thing as a good programming book. Chapter 3, the best chapter (not by Martin Fowler but by Kent Beck), &#8220;Bad Smells in Code&#8221;, tells you in only a few pages so many of the reasons why bad code might be bad and what to do about it. The bulk of the book is a catalog of refactorings, not as inspiring reading as chapter 3 but as essential to good programming as (they tell me) standard openings are to playing chess. Practice them until they&#8217;re part of you.</p>
<p><a href="http://www.amazon.com/Object-Oriented-Software-Construction-Book-CD-ROM/dp/0136291554/">Object-Oriented Software Construction, second edition, Bertrand Meyer, 1997.</a> (Amazon&#8217;s page says 2000, but appears to describe the same second edition.) A rare exception to the rule that good books are short. This thousand-pager taught me how to think about object-oriented programs and how to design classes (Meyer codified the Open-Closed Principle) and methods (he also codified command-query separation and Design by Contract), and much more. Even agilists need to know good design when they back in to it, and this book goes a long way towards teaching us how. For those in a hurry, or who can&#8217;t find a copy of OOSC, <a href="http://www.amazon.com/Design-Contract-Example-Richard-Mitchell/dp/0201634600/">Mitchell and McKim&#8217;s Design by Contract by Example (2001)</a> covers many of Meyer&#8217;s high points and has the advantages of being short and in print, although it lacks OOSC&#8217;s sweep and impact.</p>
<p>I was lucky enough to have some smart people point out to me Robert C. Martin&#8217;s paper <a href="http://objectmentor.com/resources/articles/Principles_and_Patterns.pdf">&#8220;Design Principles and Design Patterns&#8221; (2000)</a> (linked to, along with other good stuff, <a href="http://objectmentor.com/resources/publishedArticles.html">here</a>) at a time when I badly needed its explanation of software stability. It is easily the most important writing on object-oriented design since OOSC, introducing rationally derived principles not just of class-level design but of architecture. <a href="http://www.amazon.com/Software-Development-Principles-Patterns-Practices/">Agile Software Development (Martin et al., 2001)</a> has a more thoroughly developed version of the same material, along with discussions of agile practices and some design patterns.</p>
<p><a href="http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/">Code Complete, Steve McConnell, 1993</a> (!). This is the definitive guide to writing code line by line. It discusses in detail the best ways to declare variables, use control structures, name methods and even format code. Some details are language-specific but their rationales can be easily adapted to whatever language you&#8217;re using. Although my first edition barely seems dated, if you insist on something more recent there is a second edition (which I haven&#8217;t read, so caveat lector) and <a href="http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/">Robert C. Martin&#8217;s Clean Code (2009)</a> (which I have) does a reasonable job of serving the same purpose.</p>
<p><a href="http://www.amazon.com/Continuous-Delivery-Deployment-Automation-Addison-Wesley/dp/0321601912/">Continuous Delivery, Jez Humble and David Farley, 2010.</a> Covering source code control, automated testing, continuous integration and automated deployment, this book accomplishes the hat trick of summarizing many practical aspects of managing and delivering software which I had to learn the hard way over many years, doing so clearly and insightfully enough that I appreciate its treatment even of familiar material, and integrating enough current thinking on distributed version control and short-cycle delivery that there is plenty to learn here even for long-time CI devotees.</p>
<p>I&#8217;ll add just one book which strays a bit up the food chain from this list&#8217;s focus on books about writing code. <a href="http://www.amazon.com/Writing-Effective-Cases-Alistair-Cockburn/dp/0201702258/">Writing Effective Use Cases, Alistair Cockburn, 2001</a>, is wonderfully clear and concise on the subject of writing down what an application needs to do to meet a user&#8217;s needs. Writing out use cases has gone with the agile wind, but anyone writing or implementing user stories needs to understand and keep in mind all of the concepts presented here.</p>
<p>Look at that &#8212; not one book on a language or framework. Not that there aren&#8217;t a few good ones, but it&#8217;s learning the fundamentals, independent of this year&#8217;s favorite technology, that really has lasting value.</p>
<p>Aside from technology-specific books, I&#8217;ve left off many that are worthwhile but not of the same exalted rank as those above (a line which I found surprisingly easy to draw), some that I know are well thought of but haven&#8217;t read yet, and some that I just dislike. If you&#8217;ve got a recommendation that you think is as valuable as the books on this list I would love to hear about it.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/daveinabottle.wordpress.com/364/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/daveinabottle.wordpress.com/364/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/daveinabottle.wordpress.com/364/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/daveinabottle.wordpress.com/364/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/daveinabottle.wordpress.com/364/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/daveinabottle.wordpress.com/364/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/daveinabottle.wordpress.com/364/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/daveinabottle.wordpress.com/364/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/daveinabottle.wordpress.com/364/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/daveinabottle.wordpress.com/364/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/daveinabottle.wordpress.com/364/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/daveinabottle.wordpress.com/364/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/daveinabottle.wordpress.com/364/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/daveinabottle.wordpress.com/364/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=364&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://daveinabottle.schweisguth.org/2011/07/16/essential-reading-for-the-modern-programmer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/48891dab622b535f3c2b4ec1c8765bed?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">dschweisguth</media:title>
		</media:content>
	</item>
		<item>
		<title>Upgrading GWW from Ruby 1.8.7 to Ruby 1.9.2 and RVM</title>
		<link>http://daveinabottle.schweisguth.org/2011/06/03/upgrading-to-ruby-1-9-2-and-rvm/</link>
		<comments>http://daveinabottle.schweisguth.org/2011/06/03/upgrading-to-ruby-1-9-2-and-rvm/#comments</comments>
		<pubDate>Sat, 04 Jun 2011 00:12:49 +0000</pubDate>
		<dc:creator>dschweisguth</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://daveinabottle.schweisguth.org/?p=327</guid>
		<description><![CDATA[Having already upgraded GWW from Rails 1 to Rails 2 and then Rails 3, the last step to bring it fully up to date was to upgrade to Ruby 1.9.2. It wasn&#8217;t difficult, but it took enough puzzling out to be worth writing down, and I even found a regression in Ruby. Getting rspec to [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=327&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Having already upgraded <a href="https://github.com/dschweisguth/gww">GWW</a> from Rails 1 to Rails 2 and then Rails 3, the last step to bring it fully up to date was to upgrade to Ruby 1.9.2. It wasn&#8217;t difficult, but it took enough puzzling out to be worth writing down, and I even found a regression in Ruby.</p>
<p><span id="more-327"></span></p>
<h3>Getting rspec to run</h3>
<p>I installed rvm on my development machine per <a href="https://rvm.beginrescueend.com/">the instructions</a> and ran the specs. They refused to run, complaining about &#8220;invalid multibyte char&#8221;s in several files. <a href="http://daveinabottle.schweisguth.org/2011/02/16/latin1-utf8-rails-2-3-9-and-mysql2/">The multibyte chars were there on purpose, to test that they made it in to and out of MySQL correctly.</a> It turns out that while Ruby 1.8.7 obligingly handled UTF-8 in source files, 1.9.2 is strict and does not. The solution is to declare that the entire source file is UTF-8 with this comment on the first line:</p>
<pre># encoding: UTF-8</pre>
<p><code><br />
</code>That fixed the encoding errors, but rspec still didn&#8217;t run:</p>
<pre>&gt; rake spec
(in /Users/dave/data/projects/gww/git)
/Users/dave/.rvm/gems/ruby-1.9.2-p180@global/gems/rake-0.8.7/lib/rake.rb:32:
  warning: already initialized constant RAKEVERSION
/Users/dave/.rvm/gems/ruby-1.9.2-p180@global/gems/rake-0.8.7/lib/rake/alt_system.rb:32:
  warning: already initialized constant WINDOWS
WARNING: Possible conflict with Rake extension: String#ext already exists
WARNING: Possible conflict with Rake extension: String#pathmap already exists
/Users/dave/.rvm/gems/ruby-1.9.2-p180@global/gems/rake-0.8.7/lib/rake.rb:404:
  warning: already initialized constant EMPTY_TASK_ARGS
[a screenful of already initialized constants later ...]
rake aborted!
stack level too deep</pre>
<p><code><br />
</code>These errors came from confusion among the many copies of rake installed by Apple, rvm and GWW&#8217;s Gemfile. Fortunately I&#8217;d seen some recent blog posts on the rake 0.9 debacle which reminded bundler users that we should really have been running rake with</p>
<pre>&gt; bundle exec rake spec</pre>
<p><code><br />
</code>(or whatever target) all along, and indeed using bundle exec fixed the errors and allowed rspec to run. Of course some individual specs were still failing.</p>
<h3>Getting all of the specs to pass</h3>
<p>The most common breakage came from code like this:</p>
<pre>describe LocationParser
  it "finds a plain address" do
    text = '555 California'
    LocationParser.new([]).parse(text).should ==
      [ Address.new text, '555', 'California', nil ]
  end
end</pre>
<p><code><br />
</code>The spec (this example happens to be a spec, but the issue is not rspec-specific) had passed in 1.8.7, but in 1.9.2 it failed like so:</p>
<pre>/Users/dave/.rvm/gems/ruby-1.9.2-p180/gems/rspec-core-2.5.1/lib/rspec/core/configuration.rb:386:in `load':
  /Users/dave/data/projects/gww/git/spec/lib/location_parser_spec.rb:33:
  syntax error, unexpected tIDENTIFIER, expecting ']' (SyntaxError)</pre>
<p><code><br />
</code>The fix was simply to add parentheses around the arguments to <code>Address.new</code>. This seems to be <a href="http://redmine.ruby-lang.org/issues/4561">a bug in Ruby 1.9.2</a>. We&#8217;ll see what the Ruby team thinks. Meanwhile it&#8217;s easy enough to work around.</p>
<p>A few specs that used <a href="https://github.com/btakita/rr">RR (Double Ruby)</a> had problems. One type of problem occurred when for example I chained query methods in a controller</p>
<pre>photos = Photo.where(:person =&gt; @person).order(:dateadded)</pre>
<p><code><br />
</code>and stubbed it with RR&#8217;s double graphs:</p>
<pre>stub(Photo).where.stub!.order { [ photo ] }</pre>
<p><code><br />
</code>Specs that did this failed with</p>
<pre>NotImplementedError: super from singleton method that is defined to multiple classes is not supported;
  this will be fixed in 1.9.3 or later</pre>
<p><code><br />
</code>Caught red-handed! Those chained query methods didn&#8217;t belong in controllers anyway. I extracted them into model methods which I could then stub in the usual way.</p>
<p>The other RR problem was in a spec that stubbed the value of <code>1.day.ago</code> with this RR construct</p>
<pre>any_instance_of(ActiveSupport::Duration) do |d|
   stub(d).ago { Time.local(2011) }
end</pre>
<p><code><br />
</code>It failed with this error:</p>
<pre>ActionView::Template::Error: uninitialized constant ActiveSupport::Duration::RR</pre>
<p><code><br />
</code>This only happened one place in the application so I didn&#8217;t look in to it at all. I just replaced <code>1.day.ago</code> with <code>Time.now - 1.day</code>, stubbed <code>Time.now</code> and moved on.</p>
<p>The very last class of spec failures was an odd one. A couple of controllers converted some model objects to JSON to be inserted into a page. Their specs tested that the JSON contained what it should like so:</p>
<pre>json = {
  'id' =&gt; photo.id,
  'latitude' =&gt; photo.latitude,
  'longitude' =&gt; photo.longitude,
  'color' =&gt; 'FFFF00',
  'symbol' =&gt; '?'
}.to_json
assigns[:json].should == json</pre>
<p><code><br />
</code>Under 1.9.2 this spec failed, with the expected and emitted JSON Strings containing the same data but in different order. A tour of <code>to_json</code>, which treats hashes and ActiveRecord objects even more differently than I expected, convinced me that I wasn&#8217;t able to control the order, so I settled for this somewhat uglier alternative:</p>
<pre>json = {
  'id' =&gt; photo.id,
  'latitude' =&gt; photo.latitude.to_s, # because BigDecimals are strings in JSON
  'longitude' =&gt; photo.longitude.to_s,
  'color' =&gt; 'FFFF00',
  'symbol' =&gt; '?'
}
ActiveSupport::JSON.decode(assigns[:json]).should == json</pre>
<p><code><br />
</code>With that, all of the specs passed. Amusingly, almost every change I&#8217;d needed to make had been in the specs; I&#8217;d barely needed to touch the actual code.</p>
<p>There was one thing left to fix before moving on to production: Ruby 1.9.2 warns about suboptimal regular expressions, and GWW had one. A regexp containing something like <code>(?:\w+)?</code> produced this warning:</p>
<pre>nested repeat operator + and ? was replaced with '*'</pre>
<p><code><br />
</code>In some cases of this warning the right thing to do would be to rewrite the regexp to use <code>*</code> instead of <code>(?:)?</code> and <code>+</code>. In this case, the <code>(?:)?</code> happened to be completely unnecessary and I just removed it.</p>
<h3>Deploying to production</h3>
<p>Switching the production instance to 1.9.2 was easy. I just installed rvm (multi-user this time) and followed <a href="http://beginrescueend.com/integration/passenger/">the RVM/Passenger integration instructions</a>. In my hands Passenger does need an <code>.rvmrc</code> in the project root and the <code>config/setup_load_paths.rb</code> given in those instructions.</p>
<h3>RVM and TeamCity</h3>
<p>I left GWW&#8217;s continuous integration for last. GWW uses TeamCity. It has a simple three-step build: it <code>bundle install</code>s, it copies <code>database.yml</code> into place and it does <code>rake db:migrate spec:rcov</code>.</p>
<ul>
<li>TeamCity doesn&#8217;t yet have good rvm support. To use an rvm Ruby in TeamCity, one needs to manually set in TeamCity all of the environment variables that rvm would have set. Fortunately Jonah at Carbon Five had already documented them in <a href="http://blog.carbonfive.com/2010/08/05/using-rvm-on-teamcity-build-agents/">a nice blog post</a>. With fake rvm in the environment the <code>bundle install</code> step ran without error.</li>
<li>The other issue which showed up only in TeamCity was that <code>rake db:migrate</code> couldn&#8217;t log in to MySQL:</li>
</ul>
<pre>    Access denied for user 'root'@'localhost' (using password: NO)</pre>
<p><code><br />
</code></p>
<p style="padding-left:30px;">Rails was finding <code>config/database.yml</code>, but it was only seeing the parameters in that file&#8217;s default section, the adapter and host. That&#8217;s <a href="http://pivotallabs.com/users/mkocher/blog/articles/1692-yaml-psych-and-ruby-1-9-2-p180-here-there-be-dragons">this bug</a>, and the workaround was just to inline the default section. With that done CI ran green.</p>
<h3>Code coverage</h3>
<p>rcov runs without error on 1.9.2, but it warns that its results are probably not correct, and indeed GWW was drenched in bogus red. Switching to <a href="https://github.com/colszowka/simplecov">simplecov</a> was as easy as possible: add one line to <code>spec_helper.rb</code> and <code>bundle exec rake spec</code> instead of <code>bundle exec rake spec:rcov</code>. simplecov puts its results in the same <code>coverage</code> directory as rcov, so nothing else had to change. As a bonus, simplecov doesn&#8217;t have a bug that rcov did (it failed to mark complex hash initializers as covered) so GWW&#8217;s coverage increased to its rightful 100%.</p>
<h3>The benefits</h3>
<p>I upgraded GWW to Ruby 1.9.2 not because of any improvement in the new version, but to move to the place in the Ruby open-source ecosystem which will be the best supported for the foreseeable future. Nonetheless 1.9.2 is faster than 1.8.7; GWW&#8217;s specs now run in 13 seconds instead of 18, and longer-running processes in production saw a proportional speedup.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/daveinabottle.wordpress.com/327/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/daveinabottle.wordpress.com/327/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/daveinabottle.wordpress.com/327/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/daveinabottle.wordpress.com/327/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/daveinabottle.wordpress.com/327/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/daveinabottle.wordpress.com/327/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/daveinabottle.wordpress.com/327/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/daveinabottle.wordpress.com/327/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/daveinabottle.wordpress.com/327/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/daveinabottle.wordpress.com/327/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/daveinabottle.wordpress.com/327/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/daveinabottle.wordpress.com/327/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/daveinabottle.wordpress.com/327/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/daveinabottle.wordpress.com/327/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=327&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://daveinabottle.schweisguth.org/2011/06/03/upgrading-to-ruby-1-9-2-and-rvm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/48891dab622b535f3c2b4ec1c8765bed?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">dschweisguth</media:title>
		</media:content>
	</item>
		<item>
		<title>Succinct specs for Rails named routes</title>
		<link>http://daveinabottle.schweisguth.org/2011/05/11/succinct-specs-for-rails-named-routes/</link>
		<comments>http://daveinabottle.schweisguth.org/2011/05/11/succinct-specs-for-rails-named-routes/#comments</comments>
		<pubDate>Wed, 11 May 2011 16:48:34 +0000</pubDate>
		<dc:creator>dschweisguth</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://daveinabottle.schweisguth.org/?p=306</guid>
		<description><![CDATA[I like all of my routes tested, and I like all of my routes named, and I like all of my named routes tested. I even like to test my RESTful routes; even though it feels a bit like testing Rails, it more than paid for itself when migrating to Rails 3. How, then, to [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=306&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I like all of my routes tested, and <a href="http://daveinabottle.schweisguth.org/2011/05/11/rails-named-routes-considered-helpful/">I like all of my routes named</a>, and I like all of my named routes tested. I even like to test my RESTful routes; even though it feels a bit like testing Rails, it more than paid for itself when migrating to Rails 3. How, then, to spec a named route succinctly?</p>
<p><span id="more-306"></span>Let&#8217;s test this simple (non-RESTful) route (in <code>routes.rb</code>):</p>
<pre>get 'about' =&gt; 'root#about', :as =&gt; root_about</pre>
<p><code><br />
</code>There are two things about it to test: that the route connects to the correct controller and action, and that the name refers to the correct route. Stock RSpec tests the wiring like this:</p>
<pre>describe RootController do
  describe '#about' do
    it "routes GET /about to root#about"
      { :get =&gt; '/about' }.should route_to :controller =&gt; 'root', :action =&gt; 'about'
    end
  end
end</pre>
<p><code><br />
</code>Aside from the describe blocks (which we&#8217;re going to want in any case), that&#8217;s three lines of spec, which repeat both the URL and the route. Shoulda&#8217;s route matcher is much more succinct,</p>
<pre>describe RootController do
  describe '#about' do
    it { should route(:get, '/about').to :action =&gt; 'about' }
  end
end</pre>
<p><code><br />
</code>and it still produces a readable specification:</p>
<pre>&gt; rspec -f d spec/routing/root_routing_spec.rb
RootController
  #about
    should route GET /about to/from {:controller=&gt;"root", :action=&gt;"about"}</pre>
<p><code><br />
</code>Now for the name. Stock RSpec would test a named route something like this:</p>
<pre>describe RootController
  describe '#about'
    it "should have a route named root_about, where e.g. root_about_path == /about" do
      root_about_path.should == '/about'
    end
  end
end</pre>
<p><code><br />
</code>which is three lines for each such spec, repeating the name twice and the URL once. That seems worth a custom matcher. In <code>spec/support/matchers/routing.rb</code>:</p>
<pre>module MyApp
  module Matchers
    module Routing

      def have_named_route(name, *args)
        HaveNamedRoute.new(self, name, *args)
      end

      class HaveNamedRoute
        def initialize(context, name, *args)
          @context = context
          @name = name
          @path = "#{name}_path"
          @args = args
          if ! args.last
            raise ArgumentError, 'The last argument must be the expected uri'
          end
          @expected_uri = args.pop
        end

        def description
          "have a route named #{@name}, where e.g. #{example_call} == #{@expected_uri}"
        end

        def matches?(subject)
          @actual_uri = @context.send("#{@name}_path", *@args)
          @actual_uri == @expected_uri
        end

        def failure_message_for_should
          "expected #{example_call} to equal #{@expected_uri}, but got #{@actual_uri}"
        end

        def failure_message_for_should_not
          "expected #{example_call} to not equal #{@expected_uri}, but it did"
        end

        def example_call
          call = "#{@name}_path"
          if ! @args.empty?
            call &lt;&lt; "(#{@args.map(&amp;:to_s).join(', ')})"
          end
          call
        end

      end

    end
  end
end</pre>
<p><code><br />
</code>and now it only takes one line to specify the name while still producing the same rspec documentation output as the spec written with stock RSpec:</p>
<pre>describe RootController
  describe '#about'
    it { should have_named_route :root_about, '/about' }
  end
end</pre>
<p><code><br />
</code>So the full specification of the route and its name, putting the specification of the name first for a more logical flow, is</p>
<pre>describe RootController
  describe '#about'
    it { should have_named_route :root_about, '/about' }
    it { should route(:get, '/about').to :action =&gt; 'about' }
  end
end</pre>
<p><code><br />
</code>Not too bad; only two lines, both readable, plus context. Hmm &#8230; next time around I might write a chained matcher to do it all in one line and eliminate a level of context, but this is doing the job for now.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/daveinabottle.wordpress.com/306/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/daveinabottle.wordpress.com/306/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/daveinabottle.wordpress.com/306/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/daveinabottle.wordpress.com/306/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/daveinabottle.wordpress.com/306/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/daveinabottle.wordpress.com/306/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/daveinabottle.wordpress.com/306/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/daveinabottle.wordpress.com/306/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/daveinabottle.wordpress.com/306/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/daveinabottle.wordpress.com/306/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/daveinabottle.wordpress.com/306/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/daveinabottle.wordpress.com/306/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/daveinabottle.wordpress.com/306/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/daveinabottle.wordpress.com/306/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=306&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://daveinabottle.schweisguth.org/2011/05/11/succinct-specs-for-rails-named-routes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/48891dab622b535f3c2b4ec1c8765bed?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">dschweisguth</media:title>
		</media:content>
	</item>
		<item>
		<title>Rails&#8217; named routes considered helpful</title>
		<link>http://daveinabottle.schweisguth.org/2011/05/11/rails-named-routes-considered-helpful/</link>
		<comments>http://daveinabottle.schweisguth.org/2011/05/11/rails-named-routes-considered-helpful/#comments</comments>
		<pubDate>Wed, 11 May 2011 16:36:53 +0000</pubDate>
		<dc:creator>dschweisguth</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://daveinabottle.schweisguth.org/?p=296</guid>
		<description><![CDATA[The current Rails best practice is to use RESTful routes. One nice thing about a RESTful route is that it comes with a name. Similarly, :member and :collection routes are automatically named. But sometimes you need a plain old arbitrary route, which you can then name or not as you wish. It may seem like [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=296&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>The current Rails best practice is to use RESTful routes. One nice thing about a RESTful route is that it comes with a name. Similarly, :member and :collection routes are automatically named. But sometimes you need a plain old arbitrary route, which you can then name or not as you wish. It may seem like overkill to give every route a name, especially if the route is referred to infrequently in templates. But there&#8217;s another place where you&#8217;re virtually guaranteed to need that named route again: in tests.</p>
<p><span id="more-296"></span>Suppose your application&#8217;s home page needs to link to an about page. As with any other feature, we write the spec first (here using Webrat):</p>
<pre>describe RootController do
  render_views
  describe '#index' do
    get :index
    response.should have_selector 'a', :href =&gt; root_about, :content =&gt; 'About'
  end
end</pre>
<p><code><br />
</code>Next, implement the view. Perhaps we started with this easy specification and this is the entire contents of <code>index.html.erb</code>:</p>
<pre>&lt;%= link_to 'About', root_about %&gt;</pre>
<p><code><br />
</code>Not only is this much nicer than <code>:controller</code> and <code>:action</code>, it relieves us of having to specify twice (once in the template and once in the spec) what the route is to. Duplication eliminated before we&#8217;ve even implemented the route! To finish the thought, here&#8217;s the actual route, in <code>routes.rb</code>:</p>
<pre>get 'about' =&gt; 'root#about', :as =&gt; root_about</pre>
<p><code><br />
</code>Not a surprising choice, but we might have chosen any URL we liked without redoing any of the work we&#8217;d already done, as long as we kept the name.</p>
<p>Of course this applies to all routes, RESTful or not, and it need not apply only to view specs. Use named routes anywhere in your tests that you might have written out the URL. Except in <a href="http://daveinabottle.schweisguth.org/2011/05/11/succinct-specs-for-rails-named-routes/">routing specs</a>, of course.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/daveinabottle.wordpress.com/296/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/daveinabottle.wordpress.com/296/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/daveinabottle.wordpress.com/296/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/daveinabottle.wordpress.com/296/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/daveinabottle.wordpress.com/296/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/daveinabottle.wordpress.com/296/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/daveinabottle.wordpress.com/296/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/daveinabottle.wordpress.com/296/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/daveinabottle.wordpress.com/296/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/daveinabottle.wordpress.com/296/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/daveinabottle.wordpress.com/296/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/daveinabottle.wordpress.com/296/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/daveinabottle.wordpress.com/296/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/daveinabottle.wordpress.com/296/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=296&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://daveinabottle.schweisguth.org/2011/05/11/rails-named-routes-considered-helpful/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/48891dab622b535f3c2b4ec1c8765bed?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">dschweisguth</media:title>
		</media:content>
	</item>
		<item>
		<title>Do dynamic languages need more tests than static languages?</title>
		<link>http://daveinabottle.schweisguth.org/2011/05/02/do-dynamic-languages-need-more-tests/</link>
		<comments>http://daveinabottle.schweisguth.org/2011/05/02/do-dynamic-languages-need-more-tests/#comments</comments>
		<pubDate>Tue, 03 May 2011 02:09:46 +0000</pubDate>
		<dc:creator>dschweisguth</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://daveinabottle.schweisguth.org/?p=284</guid>
		<description><![CDATA[Recently I made an error in a Ruby program (a Rails application) that I wouldn&#8217;t have been able to make in a Java program. I renamed a model method manually &#8212; because another class had a method with the same name, and RubyMine&#8217;s Rename Method refactoring would have renamed both methods &#8212; and although I [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=284&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Recently I made an error in a Ruby program (a Rails application) that I wouldn&#8217;t have been able to make in a Java program. I renamed a model method manually &#8212; because another class had a method with the same name, and RubyMine&#8217;s Rename Method refactoring would have renamed both methods &#8212; and although I renamed the method itself and uses of the method in the model object&#8217;s spec, I missed uses of the method in a controller and mocks of it in the controller&#8217;s spec. All of the tests passed, but the application broke. &#8220;Gee,&#8221; I thought, &#8220;if I&#8217;d had to compile everything first, that couldn&#8217;t have happened.&#8221;</p>
<p><span id="more-284"></span>After a little more thought I realized that while it was true that I couldn&#8217;t have gotten that specific error past a compiler, and in fact I wouldn&#8217;t even have made it in a language that would only consider two methods of two different classes to be &#8216;the same&#8217; if they implemented a method which appeared in a supertype, that kind of error is only a small subset of a much larger category of errors that can occur in any language. Instead of calling a nonexistent method, the controller might have called the wrong method, or it might have called the right method with the wrong parameters or expected a different range of return value or a different exception than the method actually had. In Java, the controller might have called an overloaded version of the same method. To catch such errors, in a perfect world every method call would be integration-tested regardless of language. What about in our imperfect world?</p>
<p>In an application that&#8217;s fully unit-tested (a reasonable and useful thing to achieve even in an imperfect world), every method will be unit-tested with all of the combinations of inputs and outputs that are needed for the application to function, and every method X that calls another class&#8217;s method Y will be unit-tested with a mock implementation of Y which accepts a subset of the inputs and returns a superset of the outputs of the real Y, guaranteeing that the real X and the real Y will work together. X and Y must be unit-tested separately to avoid the combinatorial explosion of tests that would be required to completely cover the code if all tests ran against only real implementations, and unit tests of Y must use a mock X to achieve all of the outputs of X that are necessary to test Y and, often, for acceptable test performance.</p>
<p>But in return for these benefits we pay the price of duplication. Tests of X fully specify its behavior, but tests of Y also contain at least a partial specification of X&#8217;s behavior. Where there is duplication, copies can diverge, leading to errors. These are integration errors, and only integration tests can catch them.</p>
<p>For an integration test suite to be complete it must cover every method call from one separately unit-tested module to another, not 100% line coverage but still a lot of testing. If the application is developed driven by integration tests, that level of coverage is automatically achieved. But integration tests are generally harder to write and set up and much slower to run than unit tests, so many projects test-drive with unit tests instead of integration tests at least some of the time and compromise on something less than full integration coverage.</p>
<p>Back to the effect of language: A program in any language can be fully unit-tested. What about integration tests? If you commit to full integration coverage, you&#8217;ll catch all integration errors, again regardless of language. If you don&#8217;t have complete integration coverage, language and framework matter, because different languages and frameworks allow different types of integration errors. How much they matter is a complex qualitative question that can only be answered by experience. Not having any statistics at hand, I&#8217;ll just say that I suspect that the answer to the question posed in the title is yes, static typing does reduce the chance of integration errors, but Ruby and Rails&#8217; test-first culture more than makes up the difference, and its practitioners are happy with the tradeoff.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/daveinabottle.wordpress.com/284/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/daveinabottle.wordpress.com/284/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/daveinabottle.wordpress.com/284/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/daveinabottle.wordpress.com/284/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/daveinabottle.wordpress.com/284/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/daveinabottle.wordpress.com/284/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/daveinabottle.wordpress.com/284/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/daveinabottle.wordpress.com/284/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/daveinabottle.wordpress.com/284/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/daveinabottle.wordpress.com/284/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/daveinabottle.wordpress.com/284/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/daveinabottle.wordpress.com/284/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/daveinabottle.wordpress.com/284/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/daveinabottle.wordpress.com/284/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=284&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://daveinabottle.schweisguth.org/2011/05/02/do-dynamic-languages-need-more-tests/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/48891dab622b535f3c2b4ec1c8765bed?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">dschweisguth</media:title>
		</media:content>
	</item>
		<item>
		<title>Avoiding extra queries in ActiveRecord 3</title>
		<link>http://daveinabottle.schweisguth.org/2011/05/01/avoiding-extra-queries-in-activerecord-3/</link>
		<comments>http://daveinabottle.schweisguth.org/2011/05/01/avoiding-extra-queries-in-activerecord-3/#comments</comments>
		<pubDate>Sun, 01 May 2011 18:33:14 +0000</pubDate>
		<dc:creator>dschweisguth</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://daveinabottle.schweisguth.org/?p=265</guid>
		<description><![CDATA[ActiveRecord 3 introduces a new query interface based on Arel. The new query methods are more succinct than the old :conditions etc. syntax, and they&#8217;re easier to combine into complex queries. Scopes (formerly known as named scopes) are still present and useful, but there&#8217;s much less difference between a scope and a simple method that [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=265&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>ActiveRecord 3 introduces a new query interface based on <a href="https://github.com/rails/arel">Arel</a>. The new query methods are more succinct than the old <code>:conditions</code> etc. syntax, and they&#8217;re easier to combine into complex queries. Scopes (formerly known as named scopes) are still present and useful, but there&#8217;s much less difference between a scope and a simple method that returns a query than there was before. Along with these carrots encouraging you to rewrite all your queries there is the stick of deprecation of the old syntax in Rails 3.1 and removal in Rails 3.2, so most people migrate to the new interface when they <a href="http://daveinabottle.schweisguth.org/2011/04/04/upgrading-gww-from-rails-2-rspec-1-and-prototype-to-rails-3-rspec-2-and-jquery/">migrate to Rails 3</a>.</p>
<p>Migrating <a href="https://github.com/dschweisguth/gww">GWW</a> to the new interface went smoothly, but when I was reviewing some pages for performance recently I noticed ActiveRecord issuing some extra queries that I didn&#8217;t expect, and that weren&#8217;t necessary. Fortunately, once noticed, they were easy to eliminate.</p>
<p><span id="more-265"></span>The extra queries came about because the new query interface issues SQL lazily. If you step through this method in a debugger while watching your test log,</p>
<pre>class Photo
  def self.print_unfound_titles
    unfound_photos = where :game_status =&gt; 'unfound'
    puts (unfound_photos.map &amp;:title).join ", "
  end
end</pre>
<p><code><br />
</code></p>
<p>you&#8217;ll see that <code>unfound_photos</code> is an <code>ActiveRecord::Relation</code> rather than an Array, and it issues an SQL query only at the last possible moment, when <code>map</code> is called.</p>
<p>Lazy evaluation allows you to pass around queries and add to them without running them until you&#8217;re ready. But, as in real life, sometimes laziness results in doing more work in the long run. GWW had several situations like this</p>
<pre>class PhotosController
  def map
    @photos = Photos.order :dateadded
    first_dateadded = @photos.first.dateadded
    @photos.each { |photo| photo[:color] = color_gradient first_dateadded, photo.dateadded }
    end
  end
end
</pre>
<p><code><br />
</code></p>
<p>in which it got a list of something from the database and made some use of the first or last item before iterating over the list. In Rails 3, this issued two queries:</p>
<pre>  Photo Load (0.5ms)  SELECT `photos`.* FROM `photos` ORDER BY dateadded LIMIT 1
  Photo Load (0.3ms)  SELECT `photos`.* FROM `photos` ORDER BY dateadded</pre>
<p><code><br />
</code></p>
<p>(Note that ActiveRecord finders don&#8217;t belong in controllers. I wrote that here to illustrate my point succinctly.)</p>
<p>The old Rails 2 query, <code>Photos.all :order =&gt; :dateadded</code>, had returned an Array, and <code>.first</code> simply returned the first element. In Rails 3, <code>order</code> returned a <code>Relation</code> and <code>.first</code> returned a second, refined <code>Relation</code>. Calling <code>.dateadded</code> caused the second <code>Relation</code> to issue a SQL query, and then iterating over <code>@photos</code> caused the first <code>Relation</code> to issue a second SQL query.</p>
<p>Having noticed the problem, the solution was simple: force the first <code>Relation</code> to run its SQL right away</p>
<pre>class PhotosController
  def map
    @photos = order(:dateadded)<span style="color:#339966;">.to_a</span>
    first_dateadded = @photos.first.dateadded
    @photos.each { |photo| photo[:color] = color_gradient first_dateadded, photo.dateadded }
    end
  end
end
</pre>
<p><code><br />
</code></p>
<p>thus turning <code>.first</code> into an array reference again and eliminating the <code>LIMIT 1</code> query.</p>
<p>You can also fully load a <code>Relation</code> by calling <code>.reload</code> on it, and <code>.reload</code> returns <code>self</code> so you can chain method calls, but I find that <code>.to_a</code> better expresses that loading (not <em>re</em>loading) is taking place.</p>
<p>There are quite a few situations in which ActiveRecord loads a <code>Relation</code> only partially, and in which you might want to tell it to load fully. (I say &#8220;fully&#8221; rather than &#8220;eagerly&#8221; because the latter refers to the separate decision of whether to load associations.) Looking at <code>ActiveRecord::FinderMethods</code>, we see that some forms of <code>.first</code> load fully and some do not. <code>.last</code> generally works like <code>.first</code>, except of course for its lastness.</p>
<p>A not-yet-loaded <code>Relation</code> will also issue a reduced query when you call <code>.size</code>, <code>.empty?</code> or the blockless forms of <code>.any?</code> or <code>.many?</code>. These methods run a <code>COUNT(*)</code> query. (Oddly, <code>.length</code> always runs the full query; this seems like a bug.) As before, if you&#8217;re going to need the full query results anyway, you can eliminate the reduced query by calling <code>.to_a</code> on the Relation right away.</p>
<p>Although it&#8217;s good to know the kinds of methods that result in reduced queries, so that you have an intuition about when it might help to eliminate them, it&#8217;s probably counterproductive to try to learn all the details of the cases in which ActiveRecord might issue such a query. Furthermore, the implementation of any of those methods might change in future versions. One tactic would be to call <code>.to_a</code> in any case where an application first looks at some property of a query method&#8217;s return value and then uses the full query results, but that would be cargo cult programming. Instead, do what you were probably already doing: if the performance of a web page or other ActiveRecord-using process matters, periodically review the SQL that it issues and take whatever steps are necessary to eliminate redundant queries and address inefficient ones. There are plenty of reasons to do that besides the extra <code>LIMIT 1</code> and <code>COUNT(*)</code> queries discussed here.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/daveinabottle.wordpress.com/265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/daveinabottle.wordpress.com/265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/daveinabottle.wordpress.com/265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/daveinabottle.wordpress.com/265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/daveinabottle.wordpress.com/265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/daveinabottle.wordpress.com/265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/daveinabottle.wordpress.com/265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/daveinabottle.wordpress.com/265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/daveinabottle.wordpress.com/265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/daveinabottle.wordpress.com/265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/daveinabottle.wordpress.com/265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/daveinabottle.wordpress.com/265/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/daveinabottle.wordpress.com/265/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/daveinabottle.wordpress.com/265/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=265&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://daveinabottle.schweisguth.org/2011/05/01/avoiding-extra-queries-in-activerecord-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/48891dab622b535f3c2b4ec1c8765bed?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">dschweisguth</media:title>
		</media:content>
	</item>
		<item>
		<title>Upgrading GWW from Rails 2, RSpec 1 and prototype to Rails 3, RSpec 2 and jQuery</title>
		<link>http://daveinabottle.schweisguth.org/2011/04/04/upgrading-gww-from-rails-2-rspec-1-and-prototype-to-rails-3-rspec-2-and-jquery/</link>
		<comments>http://daveinabottle.schweisguth.org/2011/04/04/upgrading-gww-from-rails-2-rspec-1-and-prototype-to-rails-3-rspec-2-and-jquery/#comments</comments>
		<pubDate>Mon, 04 Apr 2011 16:29:50 +0000</pubDate>
		<dc:creator>dschweisguth</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://daveinabottle.schweisguth.org/?p=213</guid>
		<description><![CDATA[GWW originated on Rails 1; I upgraded it to Rails 2 last year. I&#8217;d been putting off the upgrade to Rails 3 until a bug in Phusion Passenger which breaks redirects in Apache httpd was fixed, but I want to use a database adapter which supports MySQL spatial features, and that requires Rails 3. I [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=213&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="https://github.com/dschweisguth/gww">GWW</a> originated on Rails 1; I upgraded it to Rails 2 last year. I&#8217;d been putting off the upgrade to Rails 3 until <a href="http://code.google.com/p/phusion-passenger/issues/detail?id=563">a bug in Phusion Passenger which breaks redirects in Apache httpd</a> was fixed, but I want to use <a href="http://virtuoso.rubyforge.org/activerecord-mysql2spatial-adapter/">a database adapter which supports MySQL spatial features</a>, and that requires Rails 3. I said goodbye to page caching until (crossing fingers) Passenger 3.0.6, made a branch and started editing my Gemfile.</p>
<p>Although Rails 3 has been released for more than half a year, upgrading involved many hiccups and a couple of landslides. I&#8217;d have been happy to just update my gems and be done with it, but I had to hunt around enough that it seemed worth logging what I did in case it helped someone else. I&#8217;ve kept it as short and to-the-point as I could. Although I fixed all of the deprecations that Rails 3 reported as I encountered them, I won&#8217;t mention them further, since in every case they were completely clear and fixing them only required following instructions. I&#8217;ve also left out a handful of odd little incorrectnesses in GWW which worked in Rails 2 but broke in Rails 3, since the details probably won&#8217;t interest anyone else and the fixes were obvious. Otherwise, here&#8217;s how the upgrade went.</p>
<p><span id="more-213"></span></p>
<h2>Background reading</h2>
<p>The most helpful blog posts on this topic that I found included <a href="http://www.simonecarletti.com/blog/2010/07/the-way-to-rails-3/">Simone Carletti&#8217;s excellent post on preparing for the upgrade</a>,  <a href="http://omgbloglol.com/post/353978923/the-path-to-rails-3-approaching-the-upgrade">Jeremy McAnally&#8217;s post on upgrading</a>, <a href="http://ryanbigg.com/2010/11/the-rails-3-upgrade">Ryan Bigg&#8217;s Rails 3 upgrade log</a> and <a href="http://snyderscribbles.blogspot.com/2011/01/rspec-2-changes-from-rspec-1.html">Kurt Snyder&#8217;s summary of changes between RSpec 1 and RSpec 2</a>. Thanks, all.</p>
<h2>Before the upgrade</h2>
<p>I made sure GWW&#8217;s test suite was thorough. Testing routes is critical,  since <code>routes.rb</code> changes completely. For an app that uses ERB, tests of  page content (GWW uses RSpec-Rails controller specs with, in RSpec  1-speak, <code>integrate_views</code>) are also especially valuable, since the move  to Erubis breaks lots of things.</p>
<p>If you don&#8217;t already write tests the way GWW&#8217;s are written, you probably wouldn&#8217;t want to change for the sake of the upgrade alone, but  it&#8217;s worth mentioning: GWW tests controllers and views in controller specs with (in RSpec 1 terminology) <code>integrate_views</code>. Although these tests had to change (see below), they had to change much less  than if they&#8217;d been separate tests of controllers and views. That was not at all the point of writing tests that way (it was that I think the interface between <a href="http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model">skinny controllers</a> and views is an uninteresting implementation detail, not test-worthy behavior), but it was a nice bonus. Also, GWW  uses shoulda matchers in its routing specs; as well as being more  succinct and readable than the RSpec matchers they replace, they work on  Rails 3 unchanged.</p>
<p>I upgraded some components of GWW to what Rails 3 uses, testing and deploying each independently, before upgrading Rails, to make the actual upgrade as small and short as possible:</p>
<ul>
<li>I upgraded to Rails 2.3.11. This shook out some things that would otherwise have come up when upgrading to Rails 3.</li>
<li>I upgraded the mysql gem to <a href="https://github.com/brianmario/mysql2">mysql2</a>. I&#8217;ve lost track of whether it was a recent Rails 2.3.something or Rails 3 that required this.</li>
<li>I <a href="http://gembundler.com/rails23.html">migrated to Bundler</a>. This is a good idea whether you&#8217;re planning to upgrade to Rails 3 or not.</li>
<li>Immediately before upgrading to Rails 3, I upgraded GWW production to Phusion Passenger 3.0.5.</li>
</ul>
<p>Some things that I didn&#8217;t do before the actual upgrade, but should have:</p>
<ul>
<li><a href="https://github.com/rails/rails_xss">Migrate to Erubis and the new default of escaping HTML in strings interpolated into templates.</a></li>
<li>Migrate from RSpec&#8217;s <code>have_tag</code> and <code>have_text</code> matchers to Webrat&#8217;s <code>have_selector</code> and <code>contains</code> matchers or some other RSpec 2-compatible equivalent.</li>
</ul>
<p>I don&#8217;t know of a simpler upgrade path from prototype to jQuery than rewriting all of the Javascript in mid-upgrade, which is what I ended up doing.</p>
<h2>The upgrade</h2>
<h3>Install <a href="https://github.com/rails/rails_upgrade">the rails_upgrade plugin</a></h3>
<p><code>script/plugin install git://github.com/rails/rails_upgrade.git</code>, then <code>rake rails:upgrade:check</code>, which said to do some of the things below and some other things that weren&#8217;t relevant or could wait. As mentioned above I didn&#8217;t worry about the deprecations until I ran into them.</p>
<h3>Create application.rb</h3>
<p><code>rake rails:upgrade:configuration &gt; someplace-out-of-the-way/application.rb</code></p>
<h3>Create the new <code>routes.rb</code></h3>
<p><code>rake rails:upgrade:routes &gt; someplace-out-of-the-way/routes.rb<br />
</code><br />
The generated <code>routes.rb</code> had several classes of errors which I fixed manually:</p>
<ul>
<li>It sometimes said <code>:via =&gt; get</code> when it meant <code>:via =&gt; :get</code></li>
<li>It ignored <code>:only</code> options to resources routes. Fortunately that syntax is unchanged in Rails 3 and I could just copy them over.</li>
<li>It ignored <code>:conditions</code> options on <code>with_options</code> blocks. I added more <code>:via =&gt; whatever</code> as needed.</li>
</ul>
<p>The generated <code>routes.rb</code> wasn&#8217;t well factored, either, but fixing that could wait.</p>
<h3>Back up customized files</h3>
<p><code>rake rails:upgrade:backup</code></p>
<h3>Install Rails 3</h3>
<p>I edited GWW&#8217;s Gemfile to use Rails 3.0.5, rspec 2.5.0, shoulda-matchers 1.0.0.beta2 (it had previously been using shoulda 2.11.3), webrat 0.7.3 and will_paginate 3.0.pre2 and ran <code>bundle install</code>.</p>
<h3>Generate a Rails 3 application on top of the existing Rails 2 application</h3>
<p><code>rails new .</code></p>
<p>I let it overwrite anything it wanted, backing it up manually first if it hadn&#8217;t already been backed up by <code>rake rails:upgrade:backup</code>.</p>
<h3>Sort out the damage</h3>
<ul>
<li>I went through all of the files that were modified or not in version control, merging changes from the app&#8217;s Rails 2 version and then removing the backup.</li>
<li>I moved the <code>application.rb</code> and <code>routes.rb</code> created above to <code>config</code>.</li>
<li>The directory I was in didn&#8217;t have the name that I wanted to use for the module containing my Rack application object, so I searched for all of the places where rails_upgrade or <code>rails new .</code> had used that directory name for the module name and corrected them.</li>
<li>I removed Rails 2&#8242;s <code>config/initializers/new_rails_defaults.rb</code>, since the defaults that it sets are now actually defaults in Rails 3.</li>
<li>I removed <code>config/preinitializer.rb</code>, which integrated Bundler with Rails 2 and is obsoleted by Rails 3&#8242;s built-in Bundler integration.</li>
<li>The only script in the <code>script</code> directory in Rails 3 is <code>rails</code>; I removed all of the others, leftovers from Rails 2.</li>
<li>Finally, I removed the <code>rails_upgrade</code> plugin, since its job was done.</li>
</ul>
<h3>Start the Rails console</h3>
<p><code>rails c</code> reported some errors, mostly uninteresting. One issue that caused a few minutes of head-scratching at this stage: <a href="https://rails.lighthouseapp.com/projects/8994/tickets/6537-loading-a-helper-that-generates-a-load-error-gives-a-confusing-error-message">A bug</a> makes Rails say &#8220;Missing helper file&#8221; when it should say &#8220;required file  not found&#8221; when loading a helper module with an incorrect require. Having figured out the error message, I didn&#8217;t try to figure out why requires that worked under Rails 2 failed under Rails 3; I just fixed them.</p>
<p>After a few rounds of minor fixes, <code>rails c</code> started without errors. I added a temporary fake production database config to <code>config/database.yml</code> and went another few rounds with <code>rails c production</code>, after which it too started without errors.</p>
<h3>Configure RSpec 2 and RSpec-Rails 2</h3>
<p>I ran <code>rails g rspec:install</code> and moved customizations from the old <code>spec/spec_helper.rb</code> to the new one. Per <a href="https://github.com/rspec/rspec-rails">the instructions</a>, I</p>
<ul>
<li>made sure that <code>rspec-rails</code> was in GWW&#8217;s Gemfile&#8217;s <code>:development</code> group (which it already was for a reason not related to Rails 3 or RSpec 2)</li>
<li>removed <code>lib/tasks/rspec.rake</code>, <code>spec/spec.opts</code> and <code>spec/rcov.opts</code></li>
<li>copied the definition of the <code>spec:rcov</code> task from <code>/opt/local/lib/ruby/gems/1.8/gems/rspec-rails-2.5.0/lib/rspec/rails/tasks/rspec.rake</code> to a new task file, <code>lib/tasks/rcov.rake</code>, and modified it to unload the old <code>spec:rcov task</code> and to exclude some additional files from coverage:<br />
<code><br />
</code></p>
<pre>
require 'rspec/core'
require 'rspec/core/rake_task'

Rake.application.instance_variable_get('@tasks').delete 'spec:rcov'

namespace :spec do
  desc "Run all specs with rcov"
  RSpec::Core::RakeTask.new(:rcov =&gt; 'db:test:prepare') do |t|
    t.rcov = true
    t.pattern = "./spec/**/*_spec.rb"
    t.rcov_opts = '--exclude /gems/,/Library/,/usr/,lib/tasks,.bundle,config,/lib/rspec/,/lib/rspec-,spec/,buildAgent/plugins'
  end
end
</pre>
</li>
</ul>
<h3>Run the specs, one layer at a time, and fix issues</h3>
<p><code>rake spec:lib</code> reported errors related to a use of <code>ActiveSupport::TestCase.use_transactional_fixtures</code>. It wasn&#8217;t essential (GWW&#8217;s specs other than model specs turn off transactions just to reduce noise in the RSpec log) so I commented it out and <code>rake spec:lib</code> passed.</p>
<p><code>rake spec:routing</code> failed, complaining of &#8220;<code>undefined method `route'</code>&#8220;. <a href="http://groups.google.com/group/shoulda/browse_thread/thread/4e88acd065ac12c4/">It seems that current versions of shoulda don&#8217;t integrate quite correctly with RSpec</a>; the solution was to add <code>config.include Shoulda::Matchers::ActionController</code> to <code>spec/spec_helper.rb</code>. That fixed most of the routing tests. The remaining handful of failing routing tests were due to errors in the new <code>routes.rb</code>. (Was I glad I&#8217;d tested every route!) After fixing those <code>rake spec::routing</code> passed.</p>
<p><code>rake spec:models</code> failed with the error &#8220;<code>undefined method `add_limit!'</code>&#8221; in methods using will_paginate&#8217;s <code>paginate_by_sql</code>. That was easily fixed by upgrading will_paginate to 3.0.pre2. (I lied above; I didn&#8217;t figure out that I needed that upgrade until this point.) That was all it took to get <code>rake spec::models</code> to pass.</p>
<p><code>rake spec:helpers</code> took only a little more effort:</p>
<ul>
<li>Helper specs that set request parameters through the magic <code>params</code> variable had to be changed to use the new magic <code>controller.params</code> variable.</li>
<li>Different helpers with methods with the same name suddenly found themselves in conflict. GWW had only a few such methods, so the easy solution was to rename some of them to eliminate ambiguities.</li>
<li>Custom matchers and other modules that were included in <code>spec/spec_helper.rb</code> with the <code>:type</code> option failed to load when <code>:type</code> was an array of spec  types. Breaking each such include into one line per spec type fixed  that. For example,</li>
</ul>
<p style="padding-left:60px;"><code>config.include Photos, :type =&gt; [ :helper, :controller ]</code></p>
<p style="padding-left:30px;">became</p>
<p style="padding-left:60px;"><code>config.include Photos, :type =&gt; :helper<br />
config.include Photos, :type =&gt; :controller</code></p>
<p>Making <code>rake spec:controllers</code> pass took by far the most effort of any step so far. First, the easy parts:</p>
<ul>
<li>RSpec 1&#8242;s <code>integrate_views</code> is <code>render_views</code> in RSpec 2, a quick search-and-replace.</li>
<li>Each partial called with <code>:object</code> (which defines a local with the name of the partial) no longer saw that local. <a href="https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2358-new-smart-render-misses-arguments">I&#8217;m not sure whether this was an intentional change in Rails 3 or not</a>, but it was easy to name the local explicitly.</li>
</ul>
<p>And then the big part, which was to <code>config.include Webrat::HaveTagMatcher</code> and rewrite all of the specs that used RSpec&#8217;s <code>have_tag</code> matcher to use Webrat&#8217;s <code>have_selector</code> and <code>contains</code> matchers. I referred to <a href="https://wincent.com/wiki/Webrat_matchers">this nice cheat sheet by Wincent Colaiuta</a>.</p>
<p>The updated specs found one more problem: Since Rails 3/Erubis now escapes all expressions in templates by default, expressions which returned HTML needed to be wrapped in <code>raw()</code>.</p>
<p>With the controller specs rewritten, <code>rake spec:controllers</code> and <code>rake:spec</code> passed. Weirdly, <code>rake spec:rcov</code> failed; although it had not been necessary for <code>rake spec:models</code> to pass, <code>rake spec:rcov</code> needed <code>config.include Shoulda::Matchers::ActiveRecord</code> in <code>spec/spec_helper.rb</code>.</p>
<h3>Manual testing</h3>
<p>Now that all of the specs passed it was finally time to <code>rails s</code> GWW and look at it in a browser. It came out from under the bandages in great shape, with only a few blemishes that needed correcting:</p>
<ul>
<li>A few template expressions that didn&#8217;t want to be escaped and hadn&#8217;t been caught in tests needed to be wrapped in <code>raw()</code>.</li>
<li>The ID of the form created by the <code>button_to</code> helper had changed from <code>button-to</code> with a hyphen to <code>button_to</code> with an underscore, so some CSS and Javascript had to be updated.</li>
<li>A popup that issued an AJAX request no longer worked. Rails complained that it didn&#8217;t know how to respond to a request for <code>application/json</code>. Amusingly, the action emitted HTML, not JSON; a copy-and-paste error had made the requesting Javascript Accept: application/json. Rails 2 never noticed, but Rails 3 did, and refused. The fix was just to remove the bogus parameter.</li>
<li>Some of GWW&#8217;s HTML needs to be exact about its newlines, since it&#8217;s pasted into Flickr discussions where newlines are significant. Erubis ignores whitespace around <code>&lt;% %&gt;</code>. Where GWW&#8217;s ERB templates intentionally used <code>&lt;% %&gt;</code>, not <code>&lt;% -%&gt;</code>, to insert a newline, I needed to add a blank line.</li>
<li>The other side of the coin: Putting <code>&lt;% -%&gt;</code> at the end of a line in an ERB template suppresses the newline, but that doesn&#8217;t work in Erubis. Fortunately <code>&lt;%= -%&gt;</code> does work, so I just needed to replace each <code>&lt;% -%&gt;</code> with <code>&lt;%= -%&gt;</code>.</li>
</ul>
<h3>Just one more thing &#8230;</h3>
<p>The very last thing that had broken was autocompletion in two text fields. Autocompletion had been done by a venerable plugin which was last updated in 2007 and didn&#8217;t work with Rails 3. There seemed to be no replacement which used prototype; the leading autocomplete plugin uses jQuery. Well, the Rails team is backing jQuery these days (and who isn&#8217;t?) and I&#8217;d have migrated soon enough anyway. I installed <a href="https://github.com/indirect/jquery-rails">jquery-rails</a> and <a href="https://github.com/crowdint/rails3-jquery-autocomplete">rails3-jquery-autocomplete</a>, installed jquery-rails per the instructions (with <code>--ui</code>), picked a jQuery UI CSS file from jqueryui.com, used the new autocompleter on the autocompleted fields, and rewrote all of GWW&#8217;s custom Javascript to use jQuery instead of prototype.</p>
<p>After 2 1/2 days of work, production GWW is on Rails 3. There&#8217;s still some followup to do: refactor <code>routes.rb</code>, make use of Arel, take all of the now-redundant <code>h</code>&#8216;s out of the templates, etc. And then back to features!</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/daveinabottle.wordpress.com/213/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/daveinabottle.wordpress.com/213/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/daveinabottle.wordpress.com/213/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/daveinabottle.wordpress.com/213/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/daveinabottle.wordpress.com/213/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/daveinabottle.wordpress.com/213/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/daveinabottle.wordpress.com/213/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/daveinabottle.wordpress.com/213/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/daveinabottle.wordpress.com/213/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/daveinabottle.wordpress.com/213/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/daveinabottle.wordpress.com/213/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/daveinabottle.wordpress.com/213/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/daveinabottle.wordpress.com/213/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/daveinabottle.wordpress.com/213/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=213&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://daveinabottle.schweisguth.org/2011/04/04/upgrading-gww-from-rails-2-rspec-1-and-prototype-to-rails-3-rspec-2-and-jquery/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/48891dab622b535f3c2b4ec1c8765bed?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">dschweisguth</media:title>
		</media:content>
	</item>
		<item>
		<title>Migrating Palm application data to Android</title>
		<link>http://daveinabottle.schweisguth.org/2011/03/15/migrating-palm-application-data-to-android/</link>
		<comments>http://daveinabottle.schweisguth.org/2011/03/15/migrating-palm-application-data-to-android/#comments</comments>
		<pubDate>Wed, 16 Mar 2011 05:58:44 +0000</pubDate>
		<dc:creator>dschweisguth</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Palm]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://daveinabottle.schweisguth.org/?p=170</guid>
		<description><![CDATA[There can&#8217;t be many other people left in the world who have a Palm device whose data they want to move to something newer. I mostly used my series of Palm devices for their built-in productivity applications (Contacts, Calendar, Memos, Tasks) and I was happy with the most recent, a Treo, for six years. Although [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=170&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>There can&#8217;t be many other people left in the world who have a Palm device whose data they want to move to something newer. I mostly used my series of Palm devices for their built-in productivity applications (Contacts, Calendar, Memos, Tasks) and I was happy with the most recent, a Treo, for six years. Although it&#8217;s surprisingly tough, having survived many falls onto concrete sidewalks with only a few scratches, I finally managed to break a few pixels in its screen recently. And the Palm Desktop software doesn&#8217;t run on Mac OS later than 10.4, so when I finally retire the older of my Mac laptops I won&#8217;t be able to sync the Treo. Time to move on.</p>
<p>Another reason I kept the Treo as long as I did is that I wasn&#8217;t looking forward to the migration. I&#8217;ve used Palms for twelve years, and I intend to keep my data. I expected it would be a significant project to move it all over. It wasn&#8217;t as bad as I feared &#8211;  Palm Desktop was prepared to bow out gracefully, in that it could export all of its data into standard or at least reasonable formats &#8212; but it took enough experimentation and fiddling that I&#8217;ve written it down here on the off chance that it will help someone else who still has this job ahead of them.</p>
<p><span id="more-170"></span></p>
<p>Source: Palm Treo 650 running Palm OS 5.4.8, synced to a Mac OS 10.4 laptop running Palm Desktop 4.2.1. A Mac OS 10.6 laptop pitched in too.</p>
<p>Target: Droid X running Android 2.2.1.</p>
<h2>Contacts</h2>
<p>Android&#8217;s stock Contacts application syncs with GMail contacts, so I saw no reason to look further. Palm Desktop can export contacts as vCards and GMail can import that format, so migrating from one to the other was relatively easy.</p>
<ol>
<li>Export contacts from Palm Desktop into vCard format. To preserve groups, export one group at a time, each into its own file. For example, save the Home group as <code>home.vcf</code>.</li>
<li>Comments on Palm contacts become X-Palm-Custom# lines in vCards, where # is 1, 2, 3 etc. GMail ignores these. Convert them to NOTEs, which GMail does understand, by running them through the following script. For example, <code>palm-vcf2gmail-vcf home.vcf &gt; home-gmail.vcf</code>.</li>
<li>Import each file into GMail, creating a new group for each file.</li>
<li>Go to Android Contacts and there they are, in the Google category. Sadly, the groups which I was so careful to create don&#8217;t appear on the Droid. Oh well; I can maintain them in GMail and if Android Contacts ever adds that feature I&#8217;ll be ready.</li>
</ol>
<p>The script, <code>palm-vcf2gmail-vcf</code>:</p>
<pre>#!/opt/local/bin/ruby
ARGF.each do |line|
  puts line.gsub /^X-Palm-Custom\d/, 'NOTE'
end</pre>
<p><code><br />
</code>Hmmm; I could have done that with <code>ruby -n</code>. Next time.</p>
<h2>Calendar</h2>
<p>As with contacts, Android Calendar is probably adequate for me and syncs with Google Calendar. Google Calendar imports iCal and and Outlook CSV. Palm Desktop doesn&#8217;t export either of those, but it does export vCal, and the standard Mac OS iCal application imports vCal and exports iCal.</p>
<ol>
<li>Export the calendar from Palm Desktop, saving it as e.g. <code>calendar.vcs</code>.</li>
<li>Import <code>calendar.vcs</code> into iCal, telling iCal that it&#8217;s in the vCal format. I imported into the newest version of iCal I had, 4.0.4, running on a different, newer laptop than the one running Palm Desktop, which had iCal 2.0. The two iCals export quite different iCal files, but I don&#8217;t know whether using the newer iCal made any difference.</li>
<li>Examine the results in iCal. Fix any problems in the Palm&#8217;s Calendar app, resync, re-export from Palm Desktop and re-import into iCal (in a new calendar, to avoid confusion with previous attempts). Repeat until everything that can be fixed on the Palm has been. Here&#8217;s what I had to fix:
<ul>
<li>Who knows why, but I had a handful of events which repeated, but for only one day. On the Palm these look like non-repeating events; in iCal they repeat forever. I just found each of them in the Palm and set them to not repeat.</li>
<li>I didn&#8217;t have many events with notes, because it was usually easier to just put all of the text in the event, but I had a few notes on events from before I settled in to my current usage. I just appended each note that I wanted to keep to the text of its event and deleted the note. Fortunately there weren&#8217;t many and none were long. If you need to do something different, you&#8217;ll find event notes in your memo export file (see below). No idea how to keep them attached to their events.</li>
</ul>
</li>
<li>Fix any problems in iCal that can&#8217;t be fixed on the Palm. I had one such problem: repeating no-time events that began between early November and early May turned into series of two-day events in iCal, each beginning one day too early. It didn&#8217;t take too long to fix these manually.</li>
<li>Export the calendar from iCal to a file, e.g. <code>Calendar.ics</code>.</li>
<li>Import the file into Google Calendar. The only trick here is that Google Calendar allows you to import only 5000 events per day. I had just under 5000, so I could do it once, but when I had to fix something and do it again I had to wait a day!</li>
</ol>
<p>I immediately missed Palm Calendar&#8217;s easy navigation. Google Calendar is better with two Labs add-ons: Year View and Jump to Date.</p>
<p>Afterthought: I might also have synced iCal to Google Calendar. Export and import was the first thing I tried and it worked, so I didn&#8217;t look further.</p>
<h2>Memos</h2>
<p>Android has no standard to-do application (curse the slack-jawed   target user, consuming and never producing!). I went with Note Everything, which is free, widely used and not too much more ambitious than Memos, which is all I want for now. Note Everything imports a CSV format exported by Palm Desktop for Windows, but Palm Desktop for Mac OS doesn&#8217;t export that CSV format, so I needed to convert to it myself.</p>
<ol>
<li>Export all memos from Palm Desktop to the &#8220;tab and return&#8221; format. Export only the title and body fields.</li>
<li>Convert tab-and-return to CSV using the following script, e.g. <code>tab-and-return2note-everything all.tab-and-return &gt; all.csv</code>.</li>
<li>Connect the Droid to the Mac with its USB cable and copy <code>all.csv</code> to the Droid.</li>
<li>In Note Everything, go to Menu -&gt; More -&gt; Import -&gt; Import from Palm memos and import the file.</li>
<li>The script puts all memos in the Unfiled group, since that&#8217;s where I kept all of my memos in the Palm Memo app. Now that group is useless, so move all of the memos manually from Unfiled to &#8220;Main folder&#8221; and delete Unfiled.</li>
</ol>
<p>The script, <code>tab-and-return2note-everything</code>:</p>
<pre>#!/opt/local/bin/ruby
# Converts Palm Desktop's "tab and return" export format to the CSV format that
# Note Everything expects when "importing from Palm memos".
tar = ARGF.read
lines = tar.split "\r"
lines.each do |line|
  # Skip notes attached to calendar entries
  next if line =~ /Handheld Note: Date Book/
  line.gsub! "\246", "\n"
  line.gsub! "\t", "\n"
  line.gsub! '"', '""'
  puts "\"Unfiled\", \"#{line}\""
end</pre>
<p><code><br />
</code></p>
<h2>Tasks</h2>
<p>As with Tasks, Memos has no standard Android replacement. Astrid seems to be the  only third-party to-do app which is relatively mature and can import  from a file, and then only with the not-free Power Pack add-on. Like  other third-party to-do apps, Astrid can sync with Google Tasks and  other task managment web applications, but neither Google Tasks nor the  other web apps I looked at can import tasks from a file, so that doesn&#8217;t  help.  The only recourse was to reverse-engineer Astrid&#8217;s backup format, which, fortunately, is just simple XML.</p>
<ol>
<li>Export To Dos from Palm Desktop in Tab &amp; Return format. Include  only the Category 1 and To Do columns, in that order. Save as, for  example, <code>to-do.tab-and-return</code>.</li>
<li>Convert to Astrid backup format with the following script, e.g. <code>palm2astrid to-do.tab-and-return &gt; user-110314-1600.xml</code>.</li>
<li>Copy the fake backup to the astrid directory on the Droid.</li>
<li>In Astrid, go to Menu -&gt; Backups -&gt; Import Tasks and import the fake backup.</li>
</ol>
<p>The script, <code>palm2astrid</code>:</p>
<pre>#!/opt/local/bin/ruby

def escapeHTML(string)
string.gsub! '&amp;', '&amp;amp;'
string.gsub! '&lt;', '&amp;lt;'
string.gsub! '&gt;', '&amp;gt;'
string.gsub! '"', '&amp;quot;'
end

tar = ARGF.read

puts &lt;&lt;EOS
&lt;?xml version='1.0' encoding='utf-8' ?&gt;
&lt;astrid version="174" format="2"&gt;
EOS

created = Time.now.to_i

tar.split("\r").each do |line|
line.gsub! "\255", '\''
category, text = line.split "\t"
escapeHTML category
escapeHTML text
puts &lt;&lt;EOS
&lt;task calendarUri="" completed="0" created="#{created}" deleted="0" details=" |  | &amp;lt;img src='silk_tag_pink'/&amp;gt; #{category}" detailsDate="#{created}" dueDate="0" elapsedSeconds="0" estimatedSeconds="0" flags="0" hideUntil="0" importance="2" modified="#created" notes="" postponeCount="0" recurrence="" notificationFlags="6" lastNotified="0" notifications="0" snoozeTime="0" timerStart="0" title="#{text}"&gt;
&lt;metadata created="#{created}" key="tags-tag" value="#{category}" /&gt;
&lt;/task&gt;
EOS
end

puts &lt;&lt;EOS
&lt;/astrid&gt;
EOS
</pre>
<p><code><br />
</code><br />
Note that this script will probably not work with versions of Astrid other than 3.7.2, which is what I copied the backup format from.</p>
<p>Later I ran across the Got To Do Android app, which syncs with the ToodleDo web app, which can import from a tab-and-return export of Tasks from Palm Desktop. The job is done and I&#8217;m happy with Astrid for now so this will remain the road not taken.</p>
<h2>PalmReader documents</h2>
<p>Palm Memos only handled memos up to some not very large size, and it wasn&#8217;t able to search within a memo, so I had a collection of larger text documents which I&#8217;d converted into Palm Reader format and read in Palm Reader. The situation on Android is the same: by experiment, Note Everything can handle documents up to a size of about 341Kb; it truncates larger documents on import. For documents below that size, I just copied the plain-text originals to the Droid and imported them into Note Everything using its file-at-a-time and directory-at-a-time import.</p>
<p>That left a couple of larger documents. I copied the plain-text originals of those to the Droid, too, but I read them with iReader, which handles documents up to at least 3-something Mb.</p>
<h2>Ringtone</h2>
<p>I last added a ringtone to the Treo in 2006 using phonezoo.com, and it was still there for me. I just told Phonezoo what kind of phone I had now and sent myself <a href="http://www.phonezoo.com/Ringtone.do?mid=vdAzdxuqR-4/">&#8220;Huxley Beagle Howling&#8221;</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/daveinabottle.wordpress.com/170/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/daveinabottle.wordpress.com/170/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/daveinabottle.wordpress.com/170/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/daveinabottle.wordpress.com/170/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/daveinabottle.wordpress.com/170/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/daveinabottle.wordpress.com/170/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/daveinabottle.wordpress.com/170/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/daveinabottle.wordpress.com/170/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/daveinabottle.wordpress.com/170/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/daveinabottle.wordpress.com/170/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/daveinabottle.wordpress.com/170/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/daveinabottle.wordpress.com/170/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/daveinabottle.wordpress.com/170/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/daveinabottle.wordpress.com/170/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=170&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://daveinabottle.schweisguth.org/2011/03/15/migrating-palm-application-data-to-android/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/48891dab622b535f3c2b4ec1c8765bed?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">dschweisguth</media:title>
		</media:content>
	</item>
		<item>
		<title>Page caching vs. RESTful routes in Rails</title>
		<link>http://daveinabottle.schweisguth.org/2011/03/05/page-caching-vs-restful-routes-in-rails/</link>
		<comments>http://daveinabottle.schweisguth.org/2011/03/05/page-caching-vs-restful-routes-in-rails/#comments</comments>
		<pubDate>Sun, 06 Mar 2011 01:58:44 +0000</pubDate>
		<dc:creator>dschweisguth</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://daveinabottle.schweisguth.org/?p=164</guid>
		<description><![CDATA[GWW is almost six years old. It began life on Rails 1. It&#8217;s picked up on many of the improvements to Rails made since then, but not all of them. One upgrade that remains to be done is to take more advantage of Rails&#8217; RESTful routing. (Yes, that&#8217;s a link to the Rails 2.x docs; [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=164&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="https://github.com/dschweisguth/gww">GWW</a> is almost six years old. It began life on Rails 1. It&#8217;s picked up on many of the improvements to Rails made since then, but not all of them. One upgrade that remains to be done is to take more advantage of <a href="http://guides.rubyonrails.org/v2.3.8/routing.html">Rails&#8217; RESTful routing</a>. (Yes, that&#8217;s a link to the Rails 2.x docs; GWW is waiting on <a href="http://code.google.com/p/phusion-passenger/issues/detail?id=563">a Phusion Passenger bug</a> to move to Rails 3.)</p>
<p>I recently added a new model type and set of page to GWW &#8212; it now explicitly tracks ScoreReports &#8212; and took the opportunity to begin using RESTful routes. It worked beautifully; I really appreciate being able to lay down a whole set of standard, named routes with so little code. But when I pushed the score reports tracking feature to production, it broke: creating a new score report (done by pushing a button to submit a form) did nothing, only refreshed to the index view with no new score report at the top. After a little head-scratching and watching the form submission with <a href="https://addons.mozilla.org/en-us/firefox/addon/live-http-headers/">Live HTTP Headers</a>, I realized that, like seemingly every only-in-production bug, the problem was due to caching.</p>
<p><span id="more-164"></span>In production, GWW runs under Apache httpd and Phusion Passenger, which despite the bug I mentioned have been rock-solid. Many of GWW&#8217;s pages take a little time to generate, so to speed things up most of them are cached using <a href="http://guides.rubyonrails.org/v2.3.8/caching_with_rails.html">Rails&#8217; page-caching mechanism</a>. So that cached pages don&#8217;t litter the <code>public</code> directory as they would in the default configuration, GWW puts them in <code>public/cache</code> with this line in <code>config/environments/production.rb</code>:</p>
<pre>config.action_controller.page_cache_directory = File.join(RAILS_ROOT, "public/cache")</pre>
<p><code><br />
</code></p>
<p>Passenger needs no configuration to serve cached pages from the default location in <code>public</code>, but having moved them they must be redirected to manually in <code>public/.htaccess</code>:</p>
<pre>RewriteEngine On

# If REDIRECT_STATUS is empty (not set), this request comes directly from a
# client, not from an internal redirect following one of the rewrites below.
# In that case, forbid URIs which begin with "cache" so clients can't request
# cached pages directly from the cache directory.
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^cache - [F,L]

RewriteCond %{DOCUMENT_ROOT}/cache/index.html -f
RewriteRule ^$ cache/index.html [L]

RewriteCond %{DOCUMENT_ROOT}/cache%{REQUEST_URI}.html -f
RewriteRule ^(.+)$ cache/$1.html [L]</pre>
<p><code><br />
</code></p>
<p>This worked fine until GWW acquired its first RESTful route.</p>
<p>Under the old Rails routing conventions (or at least GWW&#8217;s interpretation of them), the URI from which one would get a list of score reports would be something like <code>/score_reports/list</code> and the URI to which one would post to create a ScoreReport would be something like <code>/score_reports/create</code>. With RESTful routes, both actions use the same URI, <code>/score_reports</code>, one with HTTP method GET (exercised by clicking on a link in a browser) and one with HTTP method POST (exercised by submitting a form).</p>
<p>The bug had been in the caching configuration all along; it was just exposed for the first time by adding to the application two routes that differed only in HTTP method. The redirect to a cached page wasn&#8217;t considering the HTTP method. GETting <code>/score_reports</code> in the browser cached the page, then POSTing to <code>/score_reports</code> caused httpd to return the cached page before the request ever reached Rails.</p>
<p>Once understood the problem was easily fixed by adding a condition to rewrite only GETs:</p>
<pre>RewriteEngine On

# If REDIRECT_STATUS is empty (not set), this request comes directly from a
# client, not from an internal redirect following one of the rewrites below.
# In that case, forbid URIs which begin with "cache" so clients can't request
# cached pages directly from the cache directory.
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^cache - [F,L]

<span style="color:#008000;">RewriteCond %{REQUEST_METHOD} GET
</span>RewriteCond %{DOCUMENT_ROOT}/cache/index.html -f
RewriteRule ^$ cache/index.html [L]

<span style="color:#008000;">RewriteCond %{REQUEST_METHOD} GET
</span>RewriteCond %{DOCUMENT_ROOT}/cache%{REQUEST_URI}.html -f
RewriteRule ^(.+)$ cache/$1.html [L]</pre>
<p><code><br />
</code></p>
<p>With this configuration in place POSTing to <code>/score_reports</code> routes to <code>ScoreReportsController.create</code> as intended. In web applications in general it never makes sense to cache POSTs, PUTs or DELETEs, so GWW&#8217;s caching configuration would certainly have been this way in the first place if it had occurred to me. Oh well; better late than never.</p>
<p>Now that the first set of RESTful routes is working, I&#8217;ll look forward to converting more of GWW to use them. The tighter <code>routes.rb</code> is, the less work there will be to do when GWW moves to Rails 3.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/daveinabottle.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/daveinabottle.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/daveinabottle.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/daveinabottle.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/daveinabottle.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/daveinabottle.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/daveinabottle.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/daveinabottle.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/daveinabottle.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/daveinabottle.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/daveinabottle.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/daveinabottle.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/daveinabottle.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/daveinabottle.wordpress.com/164/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=daveinabottle.schweisguth.org&amp;blog=10835023&amp;post=164&amp;subd=daveinabottle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://daveinabottle.schweisguth.org/2011/03/05/page-caching-vs-restful-routes-in-rails/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/48891dab622b535f3c2b4ec1c8765bed?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">dschweisguth</media:title>
		</media:content>
	</item>
	</channel>
</rss>
