<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom">
 <title>Zerosum Dirt(nap)</title>
 
 <link href="http://blog.zerosum.org/" />
 <updated>2012-02-01T18:19:34-05:00</updated>
 <id>http://blog.zerosum.org/</id>
 
 <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/ZerosumDirtnap" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="zerosumdirtnap" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>The Wefunder Petition</title>
   <link href="http://blog.zerosum.org/2012/01/31/wefunder-petition.html" />
   <published>2012-01-31T00:00:00-05:00</published>
   <updated>2012-01-31T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2012/01/31/wefunder-petition</id>
   <content type="html">&lt;p&gt;Kickstarter is awesome for funding creative projects. It&amp;#8217;s one of my favorite startups at the moment, and it&amp;#8217;s important. I lurves it. But I wish I could use something like it to invest in actual companies &amp;#8211; both the tech startup variety that my friends work tirelessly on as well as the hyper local variety that make those special tapas that my neighbors are raving about.&lt;/p&gt;

&lt;p&gt;Soon, new laws may allow us to do just that.&lt;/p&gt;
&lt;img src='/images/wefunder.png' style='float: right; margin: 0 10px 0 10px;' /&gt;
&lt;p&gt;To raise awareness of these initiatives, a few friends and I tossed together the &lt;a href='http://wefunder.com/petition'&gt;Wefunder petition&lt;/a&gt; to support HR2930 and Brown&amp;#8217;s Democratizing Access to Capital Act (S.1791) that&amp;#8217;s currently being debated in the US Senate. Please go sign it (click the &amp;#8220;learn more&amp;#8221; link on the site for more background information and links).&lt;/p&gt;

&lt;p&gt;These changes could have huge impacts for both entrepreneurs and investors, allowing bold new ideas to surface and creating a ton of important jobs and opportunities. I know that sounds like marketing speak, but it&amp;#8217;s true. This matters.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;ll be going to DC next week to talk to Senator Brown&amp;#8217;s people and see what else we can do to push this forward. We&amp;#8217;ve also been fortunate enough to get some great coverage for our efforts at &lt;a href='http://boingboing.net/2012/01/30/crowdfunding-exemption-wefun.html'&gt;BoingBoing&lt;/a&gt; and &lt;a href='http://www.readwriteweb.com/start/2012/01/startups-petition-raises-3m-in.php'&gt;ReadWriteWeb&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now go sign it already and help us send a message. And thanks!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Building Android Apps with Mirah and Pindah</title>
   <link href="http://blog.zerosum.org/2011/07/24/android-apps-with-mirah-pindah.html" />
   <published>2011-07-24T00:00:00-04:00</published>
   <updated>2011-07-24T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2011/07/24/android-apps-with-mirah-pindah</id>
   <content type="html">&lt;p&gt;I gave a talk earlier today at the Beijing Ruby group today about my experiences building native Android applications with &lt;a href='http://mirah.org'&gt;Mirah&lt;/a&gt; and &lt;a href='http://github.com/mirah/pindah'&gt;Pindah&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Although I generally prefer building mobile web apps over native development when possible, Mirah is a really promising alternative to Java if you have to go native. Check out the &lt;a href='http://www.slideshare.net/zapnap/building-native-android-applications-with-mirah-and-pindah'&gt;preso&lt;/a&gt; below and get involved in the growing Mirah / Android community.&lt;/p&gt;

&lt;p&gt;&amp;#160; &lt;iframe marginheight='0' scrolling='no' src='http://www.slideshare.net/slideshow/embed_code/8675092' marginwidth='0' frameborder='0' height='355' width='425'&gt;&amp;nbsp;&lt;/iframe&gt;&lt;/p&gt;

&lt;p&gt;Make sure to grab the &lt;a href='http://github.com/zapnap/upordown'&gt;code for the example app&lt;/a&gt; on the GitHubs.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Geeks on a Train</title>
   <link href="http://blog.zerosum.org/2011/07/21/geeks-on-a-train.html" />
   <published>2011-07-21T00:00:00-04:00</published>
   <updated>2011-07-21T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2011/07/21/geeks-on-a-train</id>
   <content type="html">&lt;p&gt;&lt;a href='http://geeksonatrain.org'&gt;Geeks on a Train&lt;/a&gt; starts today!&lt;/p&gt;

&lt;p&gt;This afternoon I&amp;#8217;m leaving Dalian, Liaoning, China for a 10-day journey across China&amp;#8217;s tech ecosystem with a bunch of awesome startup founders. By train. Because &lt;a href='http://geeksonaplane.com'&gt;planes&lt;/a&gt; and &lt;a href='http://www.startupbus.com/hackathons'&gt;buses&lt;/a&gt; are so last year (kidding!)&lt;/p&gt;

&lt;p&gt;With stops scheduled in both Beijing and Shanghai and a number of events on the schedule including tech meetups, company visits, mentor meetings, and a 10x10 mini conference in each city, it&amp;#8217;s bound to be a fun &amp;#8211; and delightfully chaotic &amp;#8211; experience. I&amp;#8217;ve really been looking forward to it.&lt;/p&gt;
&lt;img src='/images/geeksonatrain.png' style='float: right; margin: 0 0 10px 10px;' /&gt;
&lt;p&gt;Geeks on a Train (affectionately referred to as &amp;#8220;GOAT&amp;#8221;) is part of the Dalian-based &lt;a href='http://chinaccelerator.com'&gt;Chinaccelerator&lt;/a&gt; program, which is a Chinese startup accelerator run by program director &lt;a href='http://twitter.com/chinaccelerator'&gt;Cyril Ebersweiler&lt;/a&gt; and the good folks at SOS Ventures. I was fortunate enough to meet them through &lt;a href='http://techstars.org'&gt;TechStars&lt;/a&gt; in 2010 and am really honored that they invited me over to work with some of the young teams that were accepted into the program this year. How could I say no?&lt;/p&gt;

&lt;p&gt;Chinaccelerator itself is much like TechStars, but with a brilliant international twist. The startups here aren&amp;#8217;t just from China, they&amp;#8217;re from all over the world, with founders from Malaysia, Canada, Italy, the Phillipines, India, and England, as well as China and the United States. It&amp;#8217;s really fascinating to experience both the similarities and differences of startup life on the other side of the world, but a couple philosophies remain as constants: heartfelt motivation and &lt;a href='http://justfuckingdoit.com/'&gt;JFDI&lt;/a&gt; are key.&lt;/p&gt;

&lt;p&gt;In the two weeks I&amp;#8217;ve been here thus far, I&amp;#8217;ve seen the founders produce some truly great work and make impressive progress. It&amp;#8217;s good stuff. There&amp;#8217;s nothing more inspiring than being trapped in a room full of crazy entrepreneurs with wildly different backgrounds who are trying to change the world.&lt;/p&gt;

&lt;p&gt;But I can only imagine what it&amp;#8217;s going to be like trapped on an overnight train with them :).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rails Rumble Alumni Archive Project</title>
   <link href="http://blog.zerosum.org/2011/07/02/rails-rumble-alumni-archive.html" />
   <published>2011-07-02T00:00:00-04:00</published>
   <updated>2011-07-02T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2011/07/02/rails-rumble-alumni-archive</id>
   <content type="html">&lt;p&gt;2011 has been a busy year so far, full of interesting contract work, side projects, research for the next startup biz, upcoming travel plans, and not-so-fun family health issues. It&amp;#8217;s also been a busy year for the other &lt;a href='http://railsrumble.com'&gt;Rails Rumble&lt;/a&gt; organizers, and as such there&amp;#8217;s currently no date set for the 2011 contest. Sorry about that :(.&lt;/p&gt;
&lt;img src='/images/rumble_logo_2010.png' alt='Rails Rumble' style='float: right; margin: 0 0 10px 5px;' /&gt;
&lt;p&gt;However, I did find a few hours last weekend to design / develop a Rumble-related mini-site that&amp;#8217;s been long, long overdue&amp;#8230;&lt;/p&gt;

&lt;p&gt;The new &lt;a href='http://archive.railsrumble.com'&gt;Rumble Alumni Archive&lt;/a&gt; is a searchable archive of websites and applications that were developed during contests past and present. It&amp;#8217;s a great way to see what entries are still online and browse them by year (2007-2010), country of origin, and award.&lt;/p&gt;

&lt;p&gt;Over 80 entries that were developed during Rumble events are still online, most of which have evolved pretty significantly since their initial weekend development sprint. For just a couple examples, check out &lt;a href='http://mocksup.com'&gt;Mocksup&lt;/a&gt;, &lt;a href='http://awesome-fontstacks.com'&gt;Awesome Fontstacks&lt;/a&gt;, and &lt;a href='http://ioumate.com'&gt;IOU Mate&lt;/a&gt; (formerly &amp;#8220;nDebted&amp;#8221;). Go &lt;a href='http://archive.railsrumble.com'&gt;poke around the archive&lt;/a&gt; to see others; there&amp;#8217;s some really great stuff in there. And please let us know (contact organizers &lt;em&gt;at&lt;/em&gt; railsrumble &lt;em&gt;dot&lt;/em&gt; com) if we&amp;#8217;ve left anybody out.&lt;/p&gt;

&lt;p&gt;I know I&amp;#8217;ve said it before, but it&amp;#8217;s really inspiring to me when I think about how many of these polished web apps started off as as disposable weekend experiments. Kick. Ass.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Song Lyrics Without the Suck</title>
   <link href="http://blog.zerosum.org/2011/06/26/song-lyrics-without-the-suck.html" />
   <published>2011-06-26T00:00:00-04:00</published>
   <updated>2011-06-26T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2011/06/26/song-lyrics-without-the-suck</id>
   <content type="html">&lt;p&gt;Over the past few years I&amp;#8217;ve been involved with a number of music-related web projects, including Loudwerkz, &lt;span class="caps"&gt;DMOD&lt;/span&gt; (&lt;span class="caps"&gt;RIP&lt;/span&gt;), and &lt;a href="http://ink19.com"&gt;Ink19&lt;/a&gt;. Although I make my living on the web and love what I do, I suppose I&amp;#8217;ve always been secretly jealous of those snobby record store employees who hear the latest cuts first, troll naive customers, and argue with their coworkers about song meanings :).&lt;/p&gt;
&lt;p&gt;Fortunately, the web has lowered the bar to all of that stuff. What would we do without Pandora, Last.fm, and (more recently) &lt;a href="http://turntable.fm"&gt;Turntable&lt;/a&gt;? The one missing piece for me has always been a &lt;strong&gt;good&lt;/strong&gt; song lyrics site. Sure, there are lots of lyrics engines on the web, but they&amp;#8217;re all dreadfully designed, spam-centric, and just scuzzy feeling in general. Search for lyrics for your favorite song on Google, and you&amp;#8217;re bound to end up looking at popup ads for diet pills.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re like me, this makes you sad. And irritated. So there I was, bitching about this on Twitter one evening, when &lt;a href="http://twitter.com/subimage"&gt;Seth Banks&lt;/a&gt; proposed that we actually do something about it. So we did.&lt;/p&gt;
&lt;p&gt;Last week, Seth and I launched &lt;a href="http://lyricful.com"&gt;Lyricful&lt;/a&gt;, which aims to be the first &lt;a href="http://sublog.subimage.com/2011/06/19/social-song-lyrics-without-the-spam"&gt;classy lyrics site&lt;/a&gt;. We started with a nice clean design and paired it with a sizable lyrics database (growing every day), an intuitive search interface, and some &lt;span class="caps"&gt;SEO&lt;/span&gt; know-how. We&amp;#8217;ve also added a few other things we felt fans would find useful, like song previews, concert information, and easy sharing features.&lt;/p&gt;
&lt;p&gt;Most importantly, Lyricful isn&amp;#8217;t running any invasive eyeball-bleeding advertising. The only ads on the site are in the form of song preview links and concert ticket referrals, relevant to the artist you&amp;#8217;re currently browsing (which directly benefits the artist). We built this for ourselves, as music lovers and fans, which means that we wanted to make it as easy as possible to get right to transcribing, discussing, and sharing your favorite lyrics.&lt;/p&gt;
&lt;p&gt;Since the soft launch, we&amp;#8217;ve started working with a number of artists who were interested in Lyricful and its sister site, &lt;a href="http://musicnewshq.com"&gt;MusicNewsHQ&lt;/a&gt;. To start with, we&amp;#8217;ve added featured / verified artist spots, which will help promote up and coming artists and ensure accuracy of the site contents. Double win. I&amp;#8217;m really looking forward to seeing how this project evolves, having both artists and their fans involved in the process. Got feedback for us? We&amp;#8217;d love to hear it!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Startup Workaway - Coworking in Costa Rica</title>
   <link href="http://blog.zerosum.org/2011/05/03/startup-workaway.html" />
   <published>2011-05-03T00:00:00-04:00</published>
   <updated>2011-05-03T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2011/05/03/startup-workaway</id>
   <content type="html">&lt;p&gt;Are you a hacker? Working on a startup? How about coworking and networking with other people who are building inspiring new stuff? Sure you do.&lt;/p&gt;
&lt;p&gt;&lt;img src="/images/costarica.jpeg" style="float: right; margin: 0 0 10px 10px;"/&gt;&lt;/p&gt;
&lt;p&gt;And who doesn&amp;#8217;t like the rain forest? See also: &lt;a href="http://nationalzoo.si.edu/Animals/SmallMammals/Exhibits/HowlerMonkeys/LoudestAnimal/default.cfm"&gt;howler monkeys&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;StartupWorkaway is something &lt;a href="http://stomp.io/nick-tommarello"&gt;Nick&lt;/a&gt;, &lt;a href="http://zachinglis.com"&gt;Zach&lt;/a&gt;, and I have been talking about for quite awhile. We actually built most of the website back in February when we rented a house together up in Quebec City during Winter Carnaval. Nick polished it up and posted it to &lt;a href="http://news.ycombinator.com/item?id=2507095"&gt;Hacker News&lt;/a&gt; the other day and the response has been pretty incredible so far.&lt;/p&gt;
&lt;p&gt;Visit &lt;a href="http://startupworkaway.com"&gt;StartupWorkaway&lt;/a&gt; for all the gory details. The application deadline is May 6th.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Easy Rails OAuth Integration Testing</title>
   <link href="http://blog.zerosum.org/2011/03/19/easy-rails-outh-integration-testing.html" />
   <published>2011-03-19T00:00:00-04:00</published>
   <updated>2011-03-19T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2011/03/19/easy-rails-outh-integration-testing</id>
   <content type="html">&lt;p&gt;A long while back I wrote a post about &lt;a href="http://blog.zerosum.org/2009/7/13/twitter-auth-integration-testing"&gt;Twitter auth integration testing&lt;/a&gt; using &lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt;. Back then OAuth was just beginning to see widespread use, but it was nowhere near as popular as it seems to be today. In my latest side project, all logins are from Twitter or Facebook because there&amp;#8217;s simply no need for local accounts (due to the nature of the app). But that also means that we needed an easy way to support third-party authentication in our integration tests.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;re using &lt;a href="https://github.com/intridea/omniauth"&gt;OmniAuth&lt;/a&gt; to handle auth here, which is absolutely awesome. And we&amp;#8217;re also using the equally-awesome &lt;a href="https://github.com/jnicklas/capybara"&gt;Capybara&lt;/a&gt; for integration testing.  Cucumber is no longer part of my standard testing repertoire. I could go into a long rambling post as to why, but chances are you already have some pretty good ideas about that. If you haven&amp;#8217;t felt that pain, and Cucumber works for you, that&amp;#8217;s great. Seriously. I&amp;#8217;m extremely happy for you.&lt;/p&gt;
&lt;p&gt;&lt;img src="/images/capybara.jpg" style="float: right; margin: 0 0 10px 10px;"/&gt;&lt;/p&gt;
&lt;p&gt;On the other hand, if you&amp;#8217;re dissatisfied&amp;#8230; Capy 1.0 comes with a swanky new &lt;a href="http://jeffkreeftmeijer.com/2011/acceptance-testing-using-capybaras-new-rspec-dsl/"&gt;minimalist RSpec-friendly acceptance testing &lt;span class="caps"&gt;DSL&lt;/span&gt;&lt;/a&gt; that you really ought to take a look at. The 1.0 gem hasn&amp;#8217;t been released yet, but you can pull it into your project directly from the GitHub source if you specify it in your Gemfile. It&amp;#8217;s really quite nice and simple, and I&amp;#8217;m very happy with it so far.&lt;/p&gt;
&lt;p&gt;If you want OAuth integration testing to be easy, you&amp;#8217;ll want to make sure you&amp;#8217;re using the OmniAuth 0.2.0 or later. Among it&amp;#8217;s many fine features is a new &lt;a href="https://github.com/intridea/omniauth/wiki/Integration-Testing"&gt;integration test_mode&lt;/a&gt; that makes testing OAuth logins less sucky than it&amp;#8217;s ever been before. Fortunately for us, Capybara and OmniAuth go together like giant chocholate swamp rat and creamy peanut butter. It pretty much works right out of the box.&lt;/p&gt;
&lt;p&gt;To demonstrate, let&amp;#8217;s add a nice little integration auth helper method that we can use in our request specs to log a user in (I like to put this in &lt;code&gt;spec/support/integration_spec_helper.rb&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module IntegrationSpecHelper
  def login_with_oauth(service = :twitter)
    visit "/auth/#{service}"
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, in your &lt;code&gt;spec_helper.rb&lt;/code&gt;, add the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RSpec.configure do |config|
  # ...
  config.include IntegrationSpecHelper, :type =&amp;gt; :request
end&lt;/code&gt;

&lt;code&gt;Capybara.default_host = 'http://example.org'&lt;/code&gt;

&lt;code&gt;OmniAuth.config.test_mode = true
OmniAuth.config.add_mock(:twitter, {
  :uid =&amp;gt; '12345',
  :nickname =&amp;gt; 'zapnap'
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, let&amp;#8217;s take a look at an example RSpec request spec that leverages this helper to test a workflow where a user login is required:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;feature 'testing oauth' do
  scenario 'should create a new tiger' do
    login_with_oauth
    visit new_tiger_path&lt;/code&gt;

&lt;code&gt;    fill_in 'tiger_name', :with =&amp;gt; 'Charlie'
    fill_in 'tiger_blood', :with =&amp;gt; 'yes'&lt;/code&gt;
    
&lt;code&gt;    click_on 'Create Tiger'&lt;/code&gt;
    
&lt;code&gt;    page.should have_content("Thanks! You are a winner!")
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#8217;s it. OmniAuth&amp;#8217;s test mode automatically mocks out the authentication workflow, allowing us to supply our own auth results hash. Requests made to the usual /auth/provider &lt;span class="caps"&gt;URL&lt;/span&gt; will redirect immediately to the provider callback, which means we never have to hit the actual provider while testing (which also means that webmock or fakeweb remain happy).&lt;/p&gt;
&lt;p&gt;This might seem simple, and it is. And that&amp;#8217;s kind of a big deal. So now we can get back to writing stuff that isn&amp;#8217;t plumbing and focusing on solving real problems ;).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Better AWS Access Control with IAM (and Fog)</title>
   <link href="http://blog.zerosum.org/2011/03/02/better-aws-access-control-with-iam-and-fog.html" />
   <published>2011-03-02T00:00:00-05:00</published>
   <updated>2011-03-02T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2011/03/02/better-aws-access-control-with-iam-and-fog</id>
   <content type="html">&lt;p&gt;Amazon are the undisputed kings of the &lt;a href="http://graysky.org/2010/06/developer-plumbing/"&gt;developer plumbing revolution&lt;/a&gt;. EC2 and S3 are so ubiquitious to deploying web applications that sometimes it seems difficult to remember when we had to self-host so much of this stuff. But sometimes managing my access keys can be a pain. Or even worse: a security hazard.&lt;/p&gt;
&lt;p&gt;On one hand, I don&amp;#8217;t want to create a new account with different billing information for every single client project demo or collaboration that I roll out. Yet on the other, I&amp;#8217;m hesitant to use my own set of keys in places where another person might have access to them. One set of keys to the entire kingdom seems like a bad idea.&lt;/p&gt;
&lt;p&gt;&lt;img src="/images/fog.png" style="float: right; margin: 0 0 0 10px;" /&gt;&lt;/p&gt;
&lt;p&gt;The solution to this problem is &lt;a href="http://aws.amazon.com/iam/" title="IAM"&gt;Amazon&amp;#8217;s Identity and Access Management&lt;/a&gt; product beta. &lt;span class="caps"&gt;IAM&lt;/span&gt; allows you to create different users and groups, and attach those to your account. So, for example, if you&amp;#8217;re a company or a group of people who needs to share a single &lt;span class="caps"&gt;AWS&lt;/span&gt; account, you could create separate identities with separate security credentials (access key ID + secret access key) for each individual. Or if you run several different projects and want to segregate those by account, you can do that too.&lt;/p&gt;
&lt;p&gt;Even better, you can control which &lt;span class="caps"&gt;AWS&lt;/span&gt; services that those users (or groups) have access to via policy documents. A common example might be giving a user identified as &amp;#8216;projectx&amp;#8217; access to only a &amp;#8216;projectx&amp;#8217; S3 bucket and no others. This way, you can keep your accounts separate, and limit them to only what they need. And if you ever need to revoke or regenerate keys because a single application is compromised, it&amp;#8217;s far less of a problem.&lt;/p&gt;
&lt;p&gt;Anyway, outside of Amazon&amp;#8217;s own &lt;a href="http://aws.amazon.com/documentation/iam/"&gt;documentation&lt;/a&gt;, I couldn&amp;#8217;t find a hell of a lot of information about using &lt;span class="caps"&gt;IAM&lt;/span&gt; in the real world, so I thought I&amp;#8217;d demonstrate how I&amp;#8217;m using it with &lt;a href="http://github.com/geemus/fog"&gt;Fog&lt;/a&gt;, which is an absolutely awesome cloud services library for Ruby.&lt;/p&gt;
&lt;p&gt;Annotated example code seems like the right way to go here. Let&amp;#8217;s generate a new &lt;span class="caps"&gt;IAM&lt;/span&gt; user and a set of keys for him, and give him permission to only a single bucket, which we&amp;#8217;ll create (note that your bucket name must be unique so don&amp;#8217;t use the sample one shown here).&lt;/p&gt;
&lt;p&gt;First, we set up the new user name and the bucket name that we want to create, and establish our &lt;span class="caps"&gt;AWS&lt;/span&gt; credentials:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;require 'fog'&lt;/code&gt;

&lt;code&gt;username = 'testuser'
bucket = 'uniquebucketname1234'&lt;/code&gt;

&lt;code&gt;aws_credentials = { 
  :aws_access_key_id =&amp;gt; 'YOUR-ACCESS-KEY-ID', 
  :aws_secret_access_key =&amp;gt; 'YOUR-SECRET-ACCESS-KEY'
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Creating a new S3 bucket is easy with Fog:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;storage = Fog::Storage.new(aws_credentials.merge(:provider =&amp;gt; 'AWS'))
storage.put_bucket(bucket)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fog also provides a lightweight wrapper around &lt;span class="caps"&gt;IAM&lt;/span&gt; &lt;span class="caps"&gt;API&lt;/span&gt; methods. Using this, we can create the new user and create an access key. Assuming this is successful, we&amp;#8217;ll end up with the user &lt;span class="caps"&gt;ARN&lt;/span&gt; (which we&amp;#8217;ll need later) and a new set of credentials.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iam = Fog::AWS::IAM.new(aws_credentials)&lt;/code&gt;

&lt;code&gt;user_response = iam.create_user(username)
key_response  = iam.create_access_key('UserName' =&amp;gt; username)&lt;/code&gt;

&lt;code&gt;access_key_id     = key_response.body['AccessKey']['AccessKeyId']
secret_access_key = key_response.body['AccessKey']['SecretAccessKey']
arn               = user_response.body['User']['Arn']&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We want to give this user the ability to manage their own keys (as shown in Amazon&amp;#8217;s &lt;a href="http://docs.amazonwebservices.com/IAM/latest/GettingStartedGuide/"&gt;Getting Started guide&lt;/a&gt; so we create our first policy document as they suggest.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iam.put_user_policy(username, 'UserKeyPolicy', {
  'Statement' =&amp;gt; [
    'Effect' =&amp;gt; 'Allow',
    'Action' =&amp;gt; 'iam:*AccessKey*',
    'Resource' =&amp;gt; arn 
  ]
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also want to grant them access to the bucket we created. But &lt;strong&gt;only&lt;/strong&gt; our bucket and no others. If you think constructing policy documents by hand is shitty, you&amp;#8217;re right. Fortunately the &lt;a href="http://awspolicygen.s3.amazonaws.com/policygen.html"&gt;&lt;span class="caps"&gt;AWS&lt;/span&gt; Policy Generator&lt;/a&gt; can help us generate the nasty bits. Check it out.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iam.put_user_policy(username, 'UserS3Policy', {
  'Statement' =&amp;gt; [
    {   
      'Effect' =&amp;gt; 'Allow',
      'Action' =&amp;gt; ['s3:*'],
      'Resource' =&amp;gt; [
        "arn:aws:s3:::#{bucket_name}",
        "arn:aws:s3:::#{bucket_name}/*"
      ]   
    }, {
      'Effect' =&amp;gt; 'Deny',
      'Action' =&amp;gt; ['s3:*'],
      'NotResource' =&amp;gt; [
        "arn:aws:s3:::#{bucket_name}",
        "arn:aws:s3:::#{bucket_name}/*"
      ]   
    }   
  ]
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, let&amp;#8217;s reset our &lt;span class="caps"&gt;IAM&lt;/span&gt; access credentials and verify we can access the bucket and upload a file to it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;aws_credentials = { 
  :aws_access_key_id =&amp;gt; access_key_id,
  :aws_secret_access_key =&amp;gt; secret_access_key
}&lt;/code&gt;

&lt;code&gt;storage = Fog::Storage.new(aws_credentials.merge(:provider =&amp;gt; 'AWS'))
storage.get_bucket(bucket)
storage.put_object(bucket, 'image.png', File.open('/path/to/image.png'))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that you can use the keys that are generated in place of your normal account keys pretty much anywhere, as demonstrated. However, if you&amp;#8217;re limiting bucket access as we&amp;#8217;ve done here, be aware that you won&amp;#8217;t be able to do a list command to retrieve all buckets accessible to a user. I had an incredibly frustrating couple of hours the other day trying to figure out why &lt;a href="http://s3tools.org/s3cmd"&gt;s3cmd&lt;/a&gt; and the &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/amazon-s3-organizers3fox/"&gt;Firefox S3 Organizer&lt;/a&gt; wouldn&amp;#8217;t work with my newly generated &lt;span class="caps"&gt;IAM&lt;/span&gt; keys, and the reason was simply that they were trying to get a list of buckets first, which was returning an access denied message. D&amp;#8217;oh. (and thanks to &lt;a href="https://github.com/crazed"&gt;crazed&lt;/a&gt; for helping me see the light on that.)&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re not a Ruby developer, or you just need command line access, you can also use the &lt;a href="http://aws.amazon.com/developertools/AWS-Identity-and-Access-Management/4143"&gt;&lt;span class="caps"&gt;IAM&lt;/span&gt; command line tools&lt;/a&gt; provided by Amazon, and you should definitely check out their &lt;a href="http://docs.amazonwebservices.com/IAM/latest/GettingStartedGuide/"&gt;Getting Started guide&lt;/a&gt;. Hopefully &lt;span class="caps"&gt;IAM&lt;/span&gt; will find its way into the &lt;a href="http://aws.amazon.com/console/"&gt;&lt;span class="caps"&gt;AWS&lt;/span&gt; Console&lt;/a&gt; so routine management tasks are a bit easier in the future. In the meantime, creating policy documents by hand is a big pain in the ass, but at least the &lt;a href="http://awspolicygen.s3.amazonaws.com/policygen.html"&gt;Policy Generator&lt;/a&gt; takes a little bit of the suck out of it.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/851664"&gt;Get the full example source&lt;/a&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Stomp in the Android Market</title>
   <link href="http://blog.zerosum.org/2011/02/26/stomp-io-android-market.html" />
   <published>2011-02-26T00:00:00-05:00</published>
   <updated>2011-02-26T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2011/02/26/stomp-io-android-market</id>
   <content type="html">&lt;p&gt;My pal and &amp;#8220;prolific prototyper&amp;#8221; Nick Tommarello just released his latest project into the wild&amp;#8230; &lt;a href="http://stomp.io"&gt;Stomp.io&lt;/a&gt; is a social adventure and travel guide that aims to make it easier for you to find fun things to do while at home or on the go. Stomp debuted at the &lt;a href="http://launch.is"&gt;Launch conference&lt;/a&gt; run by former TC50 founder Jason Calacanis, and has gotten some &lt;a href="http://www.readwriteweb.com/archives/anyone_for_squirrel_fishing_stompio_is_your_social.php"&gt;great media coverage&lt;/a&gt; over the past couple days. Like pitches? You can watch Nick&amp;#8217;s presentation &lt;a href="http://www.youtube.com/watch?feature=player_detailpage&amp;amp;v=2e_KCz-j0BA#t=3462s"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="/images/stomp.png" style="float: right; margin: 0 0 10px 10px;"/&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re in SF, &lt;span class="caps"&gt;NYC&lt;/span&gt;, or Boston, make sure to give it a try. Hopefully it won&amp;#8217;t take too long to spread to other areas too. Some of the challenges are&amp;#8230; &lt;a href="http://stomp.io/challenges/261"&gt;kind of nuts&lt;/a&gt;. Others are a bit more &lt;a href="http://stomp.io/challenges/304"&gt;laid back&lt;/a&gt;. And there&amp;#8217;s a lot more in-between so I&amp;#8217;m pretty sure you&amp;#8217;ll find &lt;a href="http://stomp.io/challenges/184-go-trampolining-at-skyzone-sports"&gt;something&lt;/a&gt; you like there.  You can install the mobile version of the app on both the &lt;a href="http://itunes.apple.com/us/app/stomp/id413204035?mt=8"&gt;iPhone&lt;/a&gt; and &lt;a href="https://market.android.com/details?id=io.stomp.android&amp;amp;feature=search_result"&gt;Android&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Oh and if you&amp;#8217;re having problems with the Android version of the app you can yell at me. Working with Nick on Stomp was a great excuse for me to level up on Android development. There&amp;#8217;s no better way to come up to speed on a new platform than to dive in and deliver a working application. That said, the app is still young and a bit sparse, and I&amp;#8217;m sure there are still a few bugs &lt;a href="http://stomp.io/challenges/125"&gt;hiding in the woods&lt;/a&gt;; Crash reports and feature requests are very welcome :). Thanks in advance!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Ohai Tumblr</title>
   <link href="http://blog.zerosum.org/2011/01/02/ohai-tumblr.html" />
   <published>2011-01-02T00:00:00-05:00</published>
   <updated>2011-01-02T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2011/01/02/ohai-tumblr</id>
   <content type="html">&lt;p&gt;At one point in time (affectionately referred to as the &amp;#8220;long long ago&amp;#8221;) I used to post all kinds of stuff here, both technical / programmery and non-technical / non-programmery. Once I started using &lt;a href="http://twitter.com/zapnap"&gt;Twitter&lt;/a&gt; on a regular basis, I stopped posting here as much, and when I did, the content was pretty much just technical stuff. Which is a big win if you&amp;#8217;re a fan of the signal to noise ratio.&lt;/p&gt;
&lt;p&gt;&amp;#8220;But,&amp;#8221; you say, &amp;#8220;I like more noise with less signal!&amp;#8221;&lt;/p&gt;
&lt;p&gt;Me too! And thus it was that I set up a &lt;a href="http://zapnap.tumblr.com"&gt;Tumblr&lt;/a&gt; account awhile back, mostly for posting &lt;a href="http://zapnap.tumblr.com/post/2180921779/best-t-shirt-ever"&gt;stupid pictures&lt;/a&gt;. But I figured, what with it being 2011 and all, that I&amp;#8217;d maybe I&amp;#8217;d also start &lt;a href="http://zapnap.tumblr.com/post/2568587148/january-reading-list"&gt;writing a little bit more there&lt;/a&gt;. Or maybe not. We&amp;#8217;ll see.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re interested, &lt;a href="http://zapnap.tumblr.com"&gt;follow me on Tumblr&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Oh, and Happy New Year!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Fooling Around with Mirah and Android</title>
   <link href="http://blog.zerosum.org/2010/12/20/mirah-and-android.html" />
   <published>2010-12-20T00:00:00-05:00</published>
   <updated>2010-12-20T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2010/12/20/mirah-and-android</id>
   <content type="html">&lt;p&gt;Have you spent any time playing around with &lt;a href="http://mirah.org"&gt;Mirah&lt;/a&gt; yet? You should. It&amp;#8217;s developing into a pretty awesome language. Or maybe just a fantastic &lt;a href="http://www.drdobbs.com/blog/archives/2010/11/mirah_ruby_synt.html"&gt;Ruby-like syntax for Java&lt;/a&gt;, depending on how you look at it. Mirah as a language (err, compiler) is still a work in progress, but it&amp;#8217;s very usable as-is and fun to play around with. &lt;br /&gt;
&lt;img src="/images/ruby-android.png" style="float:right; margin: 0 0 10px 10px;"/&gt;&lt;/p&gt;
&lt;p&gt;If nothing else, it certainly makes writing trivial Android applications more enjoyable. Want to write one yourself? Check out &lt;a href="http://github.com/zapnap/protoform"&gt;Protoform&lt;/a&gt;, a little Mirah Android app generator that I tossed together a few weeks ago. Install it via Rubygems and get your droid on:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gem install protoform
protoform -S ~/android/sdk -T "Hello Android" -P org.zerosum.android HelloWorld&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You&amp;#8217;ll want to have JRuby and Mirah installed of course. Get JRuby with &lt;a href="http://rvm.beginrescueend.com/rvm/install/"&gt;&lt;span class="caps"&gt;RVM&lt;/span&gt;&lt;/a&gt; and then gem install &lt;a href="http://github.com/mirah/mirah"&gt;Mirah&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to do Android work in straight Ruby instead, you can take a look&lt;br /&gt;
at &lt;a href="http://ruboto.org/"&gt;Ruboto&lt;/a&gt;. However, Ruboto runs on Android&lt;br /&gt;
via JRuby, which means the runtime needs to be bundled in to the &lt;span class="caps"&gt;APK&lt;/span&gt;, leading&lt;br /&gt;
to large file sizes and slow execution. Mirah, on the other hand, compiles&lt;br /&gt;
straight to Java bytecode with no middleman and makes direct use of the Google&lt;br /&gt;
Android APIs. Ruboto is under heavy development and coming along nicely though, and the more Ruby-like &lt;span class="caps"&gt;API&lt;/span&gt; wrappers are a welcome alternative.&lt;/p&gt;
&lt;p&gt;Both of these projects have the potential to be pretty important stuff. As&lt;br /&gt;
does anything else that makes mobile client development less painful&lt;br /&gt;
(&lt;a href="http://www.appcelerator.com/"&gt;Appcelerator&lt;/a&gt;, &lt;a
href="http://phonegap.com"&gt;Phonegap&lt;/a&gt;, &lt;a
href="http://rhomobile.com/"&gt;Rhomobile&lt;/a&gt;, etc).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>A Pure Git Deploy Workflow (with Jekyll and Gitolite)</title>
   <link href="http://blog.zerosum.org/2010/11/01/pure-git-deploy-workflow.html" />
   <published>2010-11-01T00:00:00-04:00</published>
   <updated>2010-11-01T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2010/11/01/pure-git-deploy-workflow</id>
   <content type="html">&lt;p&gt;Manually deploying static site updates is so 2003. And &lt;a href="http://capify.org"&gt;Capistrano&lt;/a&gt; is great, but it&amp;#8217;s an extra step you don&amp;#8217;t always need (and somewhat overcomplicated). If you&amp;#8217;re using &lt;a href="http://jekyllrb.com"&gt;Jekyll&lt;/a&gt; to power your site and already have your data in Git, it&amp;#8217;s pretty easy to set up a pure Git deployment workflow. Even if you&amp;#8217;re not using &lt;a href="http://heroku.com"&gt;Heroku&lt;/a&gt; ;-).&lt;/p&gt;
&lt;p&gt;By using either Gitosis or (better yet) &lt;a href="http://github.com/sitaramc/gitolite"&gt;Gitolite&lt;/a&gt;, you can be autodeploying like a boss in just a few minutes. And, because Gitolite allows you to manage repository access across ad-hoc groups, you can easily allow other users to push to your remotes and update the appropriate sites without them needing shell access on your server. And share those users across multiple projects, and so on and so on.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s how I set up the deploy recipe that I use for updating this blog and a couple other static sites that I&amp;#8217;m hosting on the same box.&lt;/p&gt;
&lt;h3&gt;Gitolite Installation&lt;/h3&gt;
&lt;p&gt;First, install Gitolite on the host you want to deploy to. Sitaram&amp;#8217;s &lt;a href="http://github.com/sitaramc/gitolite/blob/pu/doc/1-INSTALL.mkd"&gt;installation instructions&lt;/a&gt; are really easy to follow, but I&amp;#8217;ll summarize here (I used the root method, which I suspect is what most readers would want to use too):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clone git://github.com/sitaramc/gitolite gitolite-source
cd gitolite-source
git checkout v1.5.6 (or whatever tagged version you want)
mkdir -p /usr/local/share/gitolite/conf /usr/local/share/gitolite/hooks
src/gl-system-install /usr/local/bin /usr/local/share/gitolite/conf /usr/local/share/gitolite/hooks&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You&amp;#8217;ll need to add a &lt;code&gt;git&lt;/code&gt; user, who will own the repositories on the system. Create one now, and finish the Gitolite installation process:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;adduser git
su - git
gl-setup /path/to/your/public-key/id_rsa.pub&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Gitolite Administration&lt;/h3&gt;
&lt;p&gt;Make sure that you gave &lt;code&gt;gl-setup&lt;/code&gt; the correct public key from your local (client) system. Now, on your client, you should now be able to check out the gitolite admin repository, through which you can manage users, groups, and repository access.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git clone git@my-server:gitolite-admin&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, edit &lt;code&gt;gitolite-admin/conf/gitolite.conf&lt;/code&gt;. Gitolite comes with a couple pre-defined group definitions (including one for the admin repository; don&amp;#8217;t screw that one up). Adding a user permissions for a new repository goes like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;repo  blog
      RW+ = kyle stan&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;blog&lt;/code&gt; is the name of the repository you want to create, and &lt;code&gt;kyle&lt;/code&gt; and &lt;code&gt;stan&lt;/code&gt; are two users who will need to be able to read and write to that repository. We have no way to identify Stan and Kyle yet, but that&amp;#8217;s the next step. We&amp;#8217;ll add their public keys to the &lt;code&gt;gitolite-admin/keydir&lt;/code&gt; directory. Make sure to name them &lt;code&gt;kyle.pub&lt;/code&gt; and &lt;code&gt;stan.pub&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Add the new files to the git repo (&lt;code&gt;git add .&lt;/code&gt;) and commit everything. Push it to the remote with &lt;code&gt;git push origin master&lt;/code&gt;. This should push the gitolite admin changes back to your remote server and update the internal configuration, allowing Stan and Kyle to work on the blog project.&lt;/p&gt;
&lt;h3&gt;Managing a Static Site&lt;/h3&gt;
&lt;p&gt;For simplicity&amp;#8217;s sake, let&amp;#8217;s say that you&amp;#8217;re Stan (Stan&amp;#8217;s public key is your public key). To create the new repository and register it with Gitolite, you should now be able to do the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir blog
cd blog
git init
touch index.html
git add .
git commit -a
git remote add origin git@my-server:blog
git push origin master&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of just creating an empty index file, make it a simple html file, or drop in &lt;a href="http://github.com/mojombo/jekyll/wiki/Sites"&gt;a basic Jekyll site&lt;/a&gt;. Or, instead of creating a brand new repository, just add a remote (call it &lt;code&gt;production&lt;/code&gt; perhaps?) to an existing Jekyll repository that you&amp;#8217;ve been working on. In any case, when you push those commits up, Gitolite should check that your public key is authorized to perform that operation, and (assuming that it is) create the new bare repository for you automatically. Because it&amp;#8217;s cool like that.&lt;/p&gt;
&lt;p&gt;If you have a problem with this step, check that (a) your public key is indeed mapped to a username that is authorized to RW that repository, and (b) that the name in your gitolite.conf matches the public key filename.&lt;/p&gt;
&lt;p&gt;If that all appears to be working, your next step will be to create a virtual host entry in your Apache config on the server (or your web server of choice). Here&amp;#8217;s a basic Apache vhost:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
  ServerName blog.superawesomedomainname.com
  ServerAdmin info@superawesomedomainname.com
  DocumentRoot /var/www/blog&lt;/code&gt;
  
&lt;code&gt;  ErrorLog /var/log/apache2/blog-error.log
  CustomLog /var/log/apache2/blog-access.log combined
&amp;lt;/VirtualHost&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And of course, create the docroot destination and make sure the &lt;code&gt;git&lt;/code&gt; user owns it and can write to it. Then you can enable the config and restart Apache (or nginx or whatever).&lt;/p&gt;
&lt;h3&gt;Auto-Update on Deploy&lt;/h3&gt;
&lt;p&gt;I&amp;#8217;m going to assume that we&amp;#8217;re working with Jekyll here. And you should be, because it&amp;#8217;s awesome. But if you are using some other static site generator, you can customize it pretty easily. The basic idea is that you want a post-receive hook to fire whenever the server receives a new push, and you want to regenerate the site data and redeploy it for everyone to see. This makes creating a new blog post really easy, for example.&lt;/p&gt;
&lt;p&gt;Navigate to &lt;code&gt;/home/git/repositories/blog.git/hooks&lt;/code&gt; and edit the &lt;code&gt;post-receive&lt;/code&gt; file. You may also need to &lt;code&gt;chmod ug+x&lt;/code&gt; it so it&amp;#8217;ll execute properly. Here&amp;#8217;s what goes inside:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GIT_REPO=$HOME/repositories/blog.git
TMP_GIT_CLONE=$HOME/tmp/blog
PUBLIC_WWW=/var/www/blog&lt;/code&gt;

&lt;code&gt;git clone $GIT_REPO $TMP_GIT_CLONE
cd $TMP_GIT_CLONE &amp;amp;&amp;amp; jekyll --no-auto $TMP_GIT_CLONE $PUBLIC_WWW
cd ~ &amp;amp;&amp;amp; rm -rf $TMP_GIT_CLONE&lt;/code&gt;

&lt;code&gt;find $PUBLIC_WWW -type f -print0 | xargs -0 chmod 666
find $PUBLIC_WWW -type d -print0 | xargs -0 chmod 777&lt;/code&gt;

&lt;code&gt;exit&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save that, and then commit a sample change from your client and push it to the remote. The server should fire the post-receive hook automatically when the push has finished, and regenerate the site, dumping the changes into your docroot directory for the world to see. In fact, you should even see the Jekyll generation output in the git push command output, which makes it extra easy to troubleshoot in case you&amp;#8217;re having a problem.&lt;/p&gt;
&lt;p&gt;And voila, git auto-deploy goodness.&lt;/p&gt;
&lt;p&gt;What&amp;#8217;s best about this is that it&amp;#8217;s easy to authorize new users to update a group site or blog, and manage those users all through their public keys and a simple config file. This config also makes it easy to spin up new static sites on the same host; just copy a couple configs and you&amp;#8217;re good to go (or even better, investigate &lt;a href="http://httpd.apache.org/docs/2.2/vhosts/mass.html"&gt;dynamically configured mass virtual hosting&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re self-hosting your blog with some custom blog package you should really give this type of setup a look. I like it because it&amp;#8217;s simple to manage access, incredibly quick to deploy updates, and everything is naturally stored in Git and in plaintext, so you&amp;#8217;ve always got full revision history and never have to worry about vendor lock-in or proprietary formats. Need comments? Use &lt;a href="http://disqus.com"&gt;Disqus&lt;/a&gt;. Less moving parts is almost always better. Simple is good.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>More Jekyll, Less Hyde</title>
   <link href="http://blog.zerosum.org/2010/10/30/more-jekyll-less-hyde.html" />
   <published>2010-10-30T00:00:00-04:00</published>
   <updated>2010-10-30T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2010/10/30/more-jekyll-less-hyde</id>
   <content type="html">&lt;p&gt;This blog has been running &lt;a href="http://mephistoblog.com/"&gt;Mephisto&lt;/a&gt; since 2007 or thereabouts. And it seems like the Mephisto project has been dead for just about that long too (check that link if you don&amp;#8217;t believe me).  So that&amp;#8217;s awesome. But such is life&amp;#8230; and open source.&lt;/p&gt;
&lt;p&gt;&lt;img src="/images/jekyll.jpg" alt="Dr Jekyll" style="float: right; margin: 0 0 10px 0;"/&gt;&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;#8217;ve been meaning to migrate my blog over to something else for quite some time. Switching is of course a pain in the butt so I&amp;#8217;d been puting it off, but the decommissioning of the server host this blog used to run on was finally the shove that I needed. After evaluating a few blog engine and hosted service options, I decided to go with &lt;a href="http://jekyllrb.com/"&gt;Jekyll&lt;/a&gt; . Why? Because it&amp;#8217;s simple, static, and seems to be pretty fad-proof at this point. Also, it&amp;#8217;s Halloween. So it&amp;#8217;s thematic. I considered moving stuff to Tumblr or Posterous, but the import process proved to be an obstacle. And not Halloweeny at all. In the end, Jekyll was clearly the simplest and most malleable solution, and so here we are.&lt;/p&gt;
&lt;p&gt;Moving wasn&amp;#8217;t too too painful. I whipped up a few scripts to yank the data I needed out of Mephisto and then spent a few extra hours cleaning up some sloppiness and making sure all the permalinks still worked. I ported the &lt;a href="http://nhruby.org"&gt;NH Ruby&lt;/a&gt; blog and a few other small sites that were running on a Mephisto multi-site install at the same time. I really wanted a pure Git workflow for easy deployment, so I created some post-receive hooks that auto-deploy the latest changes when someone pushes to origin/production. And because a few other people needed to be able to post to the other sites, I figured I&amp;#8217;d set up &lt;a href="http://github.com/sitaramc/gitolite"&gt;Gitolite&lt;/a&gt;, which makes managing access control for such things crazy easy.&lt;/p&gt;
&lt;p&gt;The only thing that didn&amp;#8217;t make the transition is old blog comments. I went with &lt;a href="http://disqus.com"&gt;Disqus&lt;/a&gt; for the new site because I wanted to keep everything static and simple (avoiding lock-in to yet blog package that may or may not ever be updated again), and importing the Mephisto comments into Disqus was just too much of a pain to justify the time. Sorry about that.&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;#8217;m pretty happy with the new setup. If you find anything that&amp;#8217;s broken please let me know. Maybe if I get some free time over the next couple days I&amp;#8217;ll document the Gitolite + Jekyll deployment config. I imagine that it&amp;#8217;s not completely unlike a minimalist version of what the &lt;a href="http://gitwrite.com/"&gt;GitWrite&lt;/a&gt; guys had to do for their (awesome!) Rails Rumble entry this year. And yeah, I probably could have just used them too. Don&amp;#8217;t know why I didn&amp;#8217;t think of that earlier ;-).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rails Rumble 2010</title>
   <link href="http://blog.zerosum.org/2010/10/21/rails-rumble-2010.html" />
   <published>2010-10-21T00:00:00-04:00</published>
   <updated>2010-10-21T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2010/10/21/rails-rumble-2010</id>
   <content type="html">&lt;p&gt;This is the fourth year I&amp;#8217;ve helped organize the &lt;a href="http://railsrumble.com"&gt;Rails Rumble&lt;/a&gt; innovation competition and the entries this year are definitely the best I&amp;#8217;ve seen yet. Our &lt;a href="http://blog.railsrumble.com/expert-panel"&gt;panel of experts&lt;/a&gt; have finished making their finalist selections and &lt;a href="http://blog.railsrumble.com/blog/2010/10/21/01-finalists-and-public-voting"&gt;public voting just opened&lt;/a&gt;, so head on over and help us decide who gets to do a victory dance this weekend.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Announcing RubyDoc.info</title>
   <link href="http://blog.zerosum.org/2010/8/30/rubydoc-info.html" />
   <published>2010-08-30T00:00:00-04:00</published>
   <updated>2010-08-30T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2010/8/30/rubydoc-info</id>
   <content type="html">&lt;p&gt;Last year we launched a little web service called &lt;a href="http://rdoc.info"&gt;rdoc.info&lt;/a&gt; for hosting public docs for Ruby libraries. It wasn&amp;#8217;t a completely new idea, but there was nothing else out there at the time that was free and open source and worked on Github post-commit hooks, so &lt;a href="http://blog.zerosum.org/2009/4/29/rdoc-info"&gt;I put something quick together in a day&lt;/a&gt; and started using it. A bunch of other people started using it too, which was great, and people started contributing patches, which was even more great (thanks in particular to Jeff Rafter and Brian Turnbull). It grew as more people and organizations like our friends at &lt;a href="http://robots.thoughtbot.com/post/159805485/documentation-demolition-derby"&gt;Thoughtbot&lt;/a&gt; started hosting their library docs on it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Today it hosts docs for almost 3000 different Ruby projects. And today we&amp;#8217;re killing it.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;RubyDoc.info is Rdoc.info 2.0&lt;/h3&gt;
&lt;p&gt;Well, actually, it&amp;#8217;s more like we&amp;#8217;re replacing it. With something newer and better, of course. That newer, better thing is &lt;a href="http://rubydoc.info"&gt;RubyDoc.info&lt;/a&gt; (&lt;a href="http://github.com/lsegal/rubydoc.info"&gt;source&lt;/a&gt; on Github), a project that originally started out as the &lt;a href="http://yardoc.org"&gt;yardoc.org&lt;/a&gt; doc server grew into a full-fledged rdoc.info replacement. &lt;a href="http://gnuu.org"&gt;Loren Segal&lt;/a&gt; (the author of &lt;span class="caps"&gt;YARD&lt;/span&gt;, easily the best Ruby documentation engine ever) and I have been working on merging the projects together for awhile now, and it&amp;#8217;s finally cooked well enough that we&amp;#8217;re ready to swap it over.&lt;/p&gt;
&lt;p&gt;The new site addresses a number of outstanding issues / feature enhancements that people asked for on the old site, and it&amp;#8217;s much more tied into the &lt;span class="caps"&gt;YARD&lt;/span&gt; ecosystem. Also, in addition to supporting GitHub post-commit hooks, it also hosts documentation for all published RubyGems. We like it, and we hope you do too.&lt;/p&gt;
&lt;h3&gt;If You&amp;#8217;re Already Using Rdoc.info&lt;/h3&gt;
&lt;p&gt;If your docs are already up on rdoc.info, don&amp;#8217;t worry. Your old URLs should still work, so no need to update them right away. Your post-commit hooks will still work too. If you have any problems at all, please &lt;a href="http://github.com/lsegal/rubydoc.info/issues"&gt;open a ticket&lt;/a&gt; on the project&amp;#8217;s Github repository and we&amp;#8217;ll do our best to get you squared away. Thanks!&lt;/p&gt;
&lt;h3&gt;Better Docs == Better Code&lt;/h3&gt;
&lt;p&gt;Also, in case you&amp;#8217;re not already familiar with &lt;span class="caps"&gt;YARD&lt;/span&gt;, now is a great time to learn about it and how it can help you improve documentation for your code. This new site deployment coincides with the release of the &lt;a href="http://gnuu.org/2010/08/29/announcing-yard-0-6-0/"&gt;brand new &lt;span class="caps"&gt;YARD&lt;/span&gt; 0.6&lt;/a&gt; and Loren&amp;#8217;s awesome new &lt;a href="http://yardoc.org"&gt;Yardoc.org&lt;/a&gt; site, which has some great &lt;a href="http://yardoc.org/guides/index.html"&gt;guides&lt;/a&gt; and other resources to get you up to speed fast.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Resque Mailer v1.0.0 (with Rails 3 Support)</title>
   <link href="http://blog.zerosum.org/2010/7/28/resque-mailer-v1-0-0-with-rails-3-support.html" />
   <published>2010-07-28T00:00:00-04:00</published>
   <updated>2010-07-28T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2010/7/28/resque-mailer-v1-0-0-with-rails-3-support</id>
   <content type="html">&lt;p&gt;I just released a new version of Resque Mailer (1.0.0), my asynchronous email delivery extension for Resque &lt;a href="http://rubygems.org/gems/resque_mailer"&gt;gem&lt;/a&gt; &lt;a href="http://github.com/zapnap/resque_mailer"&gt;src&lt;/a&gt;. If you&amp;#8217;re already using it with Rails 2.x, there really aren&amp;#8217;t any changes you need to be aware of. Go about your business. However, thanks largely to the efforts of &lt;a href="http://github.com/sickill"&gt;Marcin Kulik&lt;/a&gt;, the gem now works in Rails 3.x as well. Thanks Marcin!&lt;/p&gt;
&lt;p&gt;So why go 1.0.0? Because it&amp;#8217;s feature complete, used by a number of people in production, and has been stable without any significant feature additions or issues for quite some time. It&amp;#8217;s still simple as hell, and I don&amp;#8217;t see it getting more complicated any time soon. And now that it works on both Rails 2.x and 3.x, well, that sounds like a 1.0.0 to me.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Google Analytics Integration with OAuth</title>
   <link href="http://blog.zerosum.org/2010/5/28/google-analytics-integration-with-oauth.html" />
   <published>2010-05-28T00:00:00-04:00</published>
   <updated>2010-05-28T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2010/5/28/google-analytics-integration-with-oauth</id>
   <content type="html">&lt;p&gt;In case you&amp;#8217;re not reading the &lt;a href="http://blog.mogotest.com"&gt;Mogo blog&lt;/a&gt;, I posted a tutorial over there yesterday about how we &lt;a href="http://mogotest.com/blog/2010/05/27/google-analytics-integration-oauth"&gt;integrate Google Analytics with Rails using OAuth&lt;/a&gt; and &lt;a href="http://github.com/vigetlabs/garb"&gt;Garb &lt;/a&gt;. It&amp;#8217;s not a terribly arduous process, but if you haven&amp;#8217;t done much work with OAuth it can be confusing, and there are a couple unique Googly things about it that might otherwise trip you up.&lt;/p&gt;
&lt;p&gt;The post includes complete code for an OAuth-backed authorizations controller too, which should help you get up and running quickly. And fwiw, it should actually be applicable to all the Google Data APIs, not just Google Analytics. Just change the request token scope.&lt;/p&gt;
&lt;p&gt;And yeah, I really need to get back to blogging on a semi-regular basis, too.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rails Camp New England Redux</title>
   <link href="http://blog.zerosum.org/2010/3/12/rails-camp-new-england-redux.html" />
   <published>2010-03-12T00:00:00-05:00</published>
   <updated>2010-03-12T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2010/3/12/rails-camp-new-england-redux</id>
   <content type="html">&lt;p&gt;Already got plans for this weekend?&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.zerosum.org/assets/2009/7/22/yield.png" style="float: right; margin: 0 0 10px 10px"/&gt;&lt;br /&gt;
The second &lt;a href="http://railscamps.com"&gt;Rails Camp&lt;/a&gt; New England is this weekend, March 12th to the 14th, in West Greenwich Rhode Island. Hope to see some of you there! Ask me about &lt;a href="http://mogotest.com"&gt;my new startup&lt;/a&gt; (want an invite?) or help  me fix some of the outstanding &lt;a href="http://rdoc.info"&gt;Rdoc.info&lt;/a&gt; &lt;a href="http://github.com/zapnap/rdocinfo"&gt;bugs&lt;/a&gt; if you&amp;#8217;re looking for something to do :).&lt;/p&gt;
&lt;p&gt;The last camp in &lt;a href="http://blog.zerosum.org/2009/7/22/rails-camp-new-england"&gt;summer of 2009&lt;/a&gt; was a great experience and I&amp;#8217;ve been looking forward to a repeat. Thanks to &lt;a href="http://cardarella.blogspot.com/"&gt;Brian Cardarella&lt;/a&gt; for putting it together.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Resque Mailer</title>
   <link href="http://blog.zerosum.org/2010/1/9/resque-mailer.html" />
   <published>2010-01-09T00:00:00-05:00</published>
   <updated>2010-01-09T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2010/1/9/resque-mailer</id>
   <content type="html">&lt;p&gt;We&amp;#8217;ve been making heavy use of Chris Wanstrath&amp;#8217;s &lt;a href='http://github.com/defunkt/resque'&gt;Resque&lt;/a&gt; library in my &lt;a href='http://mogotest.com'&gt;latest project&lt;/a&gt;. Resque is a &lt;a href='http://code.google.com/p/redis/'&gt;Redis&lt;/a&gt;-based background job system that Chris built for GitHub. It&amp;#8217;s easy to use, especially if you&amp;#8217;re already leveraging Redis in other parts of your infrastructure, and also has a nice Sinatra front-end for monitoring job status.&lt;/p&gt;

&lt;p&gt;Anyway, Resque jobs are just Ruby classes that respond to the special perform method. They&amp;#8217;re placed on a queue &amp;#8212; you can place different jobs on different queues &amp;#8212; and later, a worker polls the queue, pops the jobs off and performs the task.&lt;/p&gt;

&lt;p&gt;We have a number of different asynchronous jobs happening in Mogo, many of which are domain-specific. But one thing we&amp;#8217;re doing that&amp;#8217;s very common is using the background system to process mail delivery asynchronously. Because synchronous mail delivery is for jerks.&lt;/p&gt;

&lt;p&gt;Outgoing mail in a Rails app is generally handled by &lt;a href='http://am.rubyonrails.org/'&gt;ActionMailer&lt;/a&gt;, which expects you to implement message delivery types as class methods on an ActionMailer &amp;#8220;model&amp;#8221; (a butchering of the term). So a typical mailer might look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Notifications &amp;lt; ActionMailer::Base

  def signup(user_id, sent_at = Time.now)
    @user = User.find(user_id)

    subject    &amp;#39;Welcome to Mogo&amp;#39;
    recipients @user.email
    from       &amp;#39;Mogoterra &amp;lt;noreply@mogoterra.com&amp;gt;&amp;#39;
    sent_on    sent_at
  end

end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, to send a signup message, you use the following method call from somewhere else in your codebase:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Notifications.deliver_signup(@user.id)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So this all works good but it&amp;#8217;s synchronous. You&amp;#8217;d like to be able to background these tasks and use Resque. But you don&amp;#8217;t really want to mess around with the mailer implementation. Right? Me too.&lt;/p&gt;

&lt;p&gt;So &lt;a href='http://github.com/zapnap/resque_mailer'&gt;ResqueMailer&lt;/a&gt; does just that.&lt;/p&gt;

&lt;p&gt;Following in the footsteps of &lt;a href='http://github.com/andersondias/delayed_job_mailer'&gt;DelayedJobMailer&lt;/a&gt;, ResqueMailer allows you to shift processing of your existing mailers to an async Resque worker without doing pretty much anything. Just install the gem in your Rails project (via &lt;a href='http://gemcutter.org/gems/resque_mailer'&gt;Gemcutter&lt;/a&gt;) and then mix the &lt;code&gt;Resque::Mailer&lt;/code&gt; module into your mailer.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Notifications &amp;lt; ActionMailer::Base
  include Resque::Mailer

  # ...
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You&amp;#8217;ll need to restart your Resque workers and make sure at least one of them is working on the special &lt;code&gt;mailer&lt;/code&gt; queue (or * for all queues). Now when you call &lt;code&gt;MyMailer.deliver_signup&lt;/code&gt;, the task will be placed on the mailer queue and processed by the first qualifying worker.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s always nice when a tiny amount of code makes a task transparent. Check out the &lt;a href='http://github.com/zapnap/resque_mailer'&gt;project page&lt;/a&gt; on GitHub for more information.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rdoc.info Updated</title>
   <link href="http://blog.zerosum.org/2009/11/22/rdoc-info-updated-2.html" />
   <published>2009-11-22T00:00:00-05:00</published>
   <updated>2009-11-22T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2009/11/22/rdoc-info-updated-2</id>
   <content type="html">&lt;p&gt;&lt;a href="http://rdoc.info"&gt;Rdoc.info&lt;/a&gt; is now serving up fresh docs using &lt;a href="http://gnuu.org/2009/11/15/yard-0-4-0-the-whole-nine/"&gt;&lt;span class="caps"&gt;YARD&lt;/span&gt; 0.4.0&lt;/a&gt;. Doesn&amp;#8217;t that new template look nice?&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.zerosum.org/assets/2009/4/22/cthulhu.png" style="float: right; padding: 0 0 5px 10px;"/&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re a Ruby &lt;span class="caps"&gt;OSS&lt;/span&gt; developer and haven&amp;#8217;t checked out &lt;a href="http://github.com/lsegal/yard"&gt;&lt;span class="caps"&gt;YARD&lt;/span&gt;&lt;/a&gt; yet, you really should. It&amp;#8217;s easily the best way to generate sexy documentation for your projects and Loren has done a really awesome job with the latest release. The experimental new &lt;a href="http://yardoc.org/docs"&gt;live docs service&lt;/a&gt; (with php.net-style user comments) that he&amp;#8217;s testing out is swanky too, and we hope to roll this stuff into Rdoc.info shortly.&lt;/p&gt;
&lt;p&gt;In the meantime, you can enjoy the latest &lt;span class="caps"&gt;YARD&lt;/span&gt; features and an updated look and feel. Make sure to &lt;a href="http://rdoc.info/projects/new"&gt;add a post-commit hook&lt;/a&gt; to your &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;-hosted project and we&amp;#8217;ll automatically rebuild docs whenever you push a new release to your remote. Docs for older versions are maintained as well, and accessible via the usual commit hash url [&lt;a href="http://rdoc.info/projects/jeffkreeftmeijer/tumblr/blob/0c9dabcf9dd9afbc442be0be573ba3a476640373"&gt;example&lt;/a&gt;].&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>EC2 Deployment with Rubber</title>
   <link href="http://blog.zerosum.org/2009/11/17/ec2-deployment-with-rubber.html" />
   <published>2009-11-17T00:00:00-05:00</published>
   <updated>2009-11-17T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2009/11/17/ec2-deployment-with-rubber</id>
   <content type="html">&lt;p&gt;At &lt;a href="http://nhruby.org"&gt;NH.rb&lt;/a&gt; last night I gave a talk about &lt;a href="http://zapnap.github.com/presentations/ec2-rubber"&gt;deploying web applications to the EC2 cloud with Rubber&lt;/a&gt;. Rubber is an extension to &lt;a href="http://capify.org"&gt;Capistrano&lt;/a&gt; written by Matt Conway that makes provisioning and managing multi-instance EC2 deployments magically delicious [&lt;a href="http://github.com/wr0ngway/rubber"&gt;GitHub&lt;/a&gt;].&lt;/p&gt;
&lt;p&gt;Want to bring up an instant multi-role staging server fully loaded with Apache, Passenger, MySQL, and your Rails app? All gem&amp;#8217;d up, migrated, and ready to use? Sure you do. First, &lt;a href="http://aws.amazon.com/ec2"&gt;sign up for an EC2 account&lt;/a&gt;, generate your keypair, and then&amp;#8230;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gem install rubber

cd my-rails-project
script/generate vulcanize complete_passenger_mysql
edit config/rubber/rubber.yml

cap rubber:create_staging
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It uses a Ubuntu &lt;span class="caps"&gt;AMI&lt;/span&gt; and provisions an EC2 small instance by default. If you added your account credentials and the apt packages and gems you needed to rubber.yml (and provided that there weren&amp;#8217;t any unexpected problems), you should now have a fully functional staging server for your web app that you can visit at http://appname.your-domain.com.&lt;/p&gt;
&lt;p&gt;Since it&amp;#8217;s EC2 you only pay for what you use. What&amp;#8217;s more is you can horizontally scale this out with relative ease &amp;mdash; breaking out the individual roles to separate instances as needed &amp;mdash; and/or add your own custom roles as needed (see the other templates available for examples).&lt;/p&gt;
&lt;p&gt;Want to learn more? Peep my &lt;a href="http://zapnap.github.com/presentations/ec2-rubber"&gt;slide deck&lt;/a&gt; and then check out the &lt;a href="http://wiki.github.com/wr0ngway/rubber"&gt;Rubber Wiki&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Reflections on *Camp</title>
   <link href="http://blog.zerosum.org/2009/11/15/reflections-on-podcamp.html" />
   <published>2009-11-15T00:00:00-05:00</published>
   <updated>2009-11-15T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2009/11/15/reflections-on-podcamp</id>
   <content type="html">&lt;p&gt;Last weekend I attended the first-ever &lt;a href="http://podcampnh.com"&gt;New Hampshire PodCamp&lt;/a&gt;, organized chiefly by my friend &lt;a href="http://twitter.com/geechee_girl"&gt;Leslie Poston&lt;/a&gt; along with a crew of enthusiastic volunteer co-organizers (myself included). I only made it to the second of the two days due to prior obligations but had a good time and enjoyed meeting everyone.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;ve never been to a PodCamp (I hadn&amp;#8217;t) it&amp;#8217;s sort of like a branded &lt;a href="http://www.barcamp.org/"&gt;BarCamp&lt;/a&gt; event that focuses more on how people are using technology &amp;mdash; such as podcasting, blogging, social networks, video and music on the web &amp;mdash; than on straight-up technical topics. I gave a presentation on &lt;a href="http://zapnap.github.com/presentations/pcnh"&gt;Developing Twitter Micro-Apps&lt;/a&gt;, which I think was pretty well received.&lt;/p&gt;
&lt;p&gt;We talked about why building apps that leverage existing social networks can be advantageous, how you can have fun with it, and how to get going really really quick with easy-to-use Ruby tools like &lt;a href="http://github.com/hayesdavis/grackle"&gt;Grackle&lt;/a&gt;, Rails templates, &lt;a href="http://github.com/mbleigh/twitter-auth"&gt;TwitterAuth&lt;/a&gt; (a Rails engine), Darcy&amp;#8217;s &lt;a href="http://github.com/sutto/BirdGrinder"&gt;BirdGrinder toolkit&lt;/a&gt;, and my own simple &lt;a href="http://github.com/zapnap/retweet"&gt;Retweet&lt;/a&gt; / Sinatra recipes. You can &lt;a href="http://zapnap.github.com/presentations/pcnh"&gt;check out the slides&lt;/a&gt; if you want to learn more.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;[ Note: The slides were made with &lt;a href="http://github.com/nakajima/slidedown"&gt;slidedown&lt;/a&gt;. Although it&amp;#8217;s still a little rough in places, it&amp;#8217;s quickly becoming my favorite tool for creating slideshows in plain text. ]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://farm3.static.flickr.com/2761/4091136470_ff2a87e9c0.jpg"/&gt;&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s me looking pretty intense, live-coding some Twittery shit during the talk. Because, I&amp;#8217;m hardcore like that. Unfortunately I didn&amp;#8217;t have anyone record the live-coding portions of the presentation, in which we built a conversation aggregator as well as a simple faux-popularity reporting service. Ah well. Other attendees gave talks on topics as various as building interactive and community television outlets on the web, Facebook app development, film promotion, digital photography, and creating Firefox add-ons.&lt;/p&gt;
&lt;p&gt;The event itself was held at the New Hampton school in &lt;del&gt;the middle of nowhere&lt;/del&gt; New Hampton, NH, which is about  an hour north of Manchester. It was quite isolated but the campus was beautiful and the solitude gave people a chance to get away from everything and kept everyone in one spot, resulting in less distractions and more focus on community. Although I really enjoy urban city-center events a lot &amp;mdash; especially when they intelligently integrate other elements of the host city into after-hours events &amp;mdash; there&amp;#8217;s something really nice about isolated rural events (the first New England &lt;a href="http://blog.zerosum.org/2009/7/22/rails-camp-new-england"&gt;Railscamp&lt;/a&gt; was another example of this)&lt;/p&gt;
&lt;p&gt;As someone who has never been very involved in organizing non-&lt;a href="http://railsrumble.com"&gt;virtual&lt;/a&gt; conferences / events before, it was also interesting to observe and assist with the process of venue selection, sponsor lineup, and so on. In short: it&amp;#8217;s a lot of work, but the payoff is great if it&amp;#8217;s done well. Congrats and a big thank-you to Leslie (and all the other co-organizers) for putting this all together. There&amp;#8217;s already talk of scheduling the next one for June 2010.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Notes from MIT Startup Bootcamp</title>
   <link href="http://blog.zerosum.org/2009/10/14/notes-from-mit-startup-bootcamp.html" />
   <published>2009-10-14T00:00:00-04:00</published>
   <updated>2009-10-14T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/10/14/notes-from-mit-startup-bootcamp</id>
   <content type="html">&lt;p&gt;Yesterday (October 12th) I attended MIT&amp;#8217;s &lt;a href="http://startupbootcamp.mit.edu/"&gt;Startup Bootcamp&lt;/a&gt;. As someone who is seriously thinking about taking some time off from his consulting lifestyle to work on bootstrapping a product, it was definitely a worthwhile event for me, and I&amp;#8217;m glad I took good notes. I thought I&amp;#8217;d share some of them in case you&amp;#8217;re interested and couldn&amp;#8217;t attend.&lt;/p&gt;
&lt;p&gt;(If you were there, and I got something wrong or you have something else to add, please leave a comment&amp;#8230;)&lt;/p&gt;
&lt;p&gt;1. &lt;a href="http://blog.adamsmith.cc/"&gt;Adam Smith&lt;/a&gt; of &lt;a href="http://www.xobni.com/"&gt;Xobni&lt;/a&gt; (a Y-Combinator company). Adam was the first speaker of the day and did a nice job relating Xobni&amp;#8217;s story. He talked at length about finding cofounders (&amp;#8220;shake the friends tree&amp;#8221;), their early days, angel funding, and achieving product-market fit. He stressed that being nimble is the key difference between successful and unsuccessful as a startup founder and mentioned how difficult &amp;mdash; but necessary &amp;mdash; it was for them to scrap an early product and change direction. &amp;#8220;Don&amp;#8217;t give up [on your idea],&amp;#8221; Adam says, &amp;#8220;90% of execution is keep going when everyone else gives up.&amp;#8221;&lt;/p&gt;
&lt;p&gt;2. &lt;a href="http://alexisohanian.com/"&gt;Alexis Ohanian&lt;/a&gt; of &lt;a href="http://reddit.com"&gt;Reddit&lt;/a&gt; (a Y-Combinator company). An energetic speaker, Alexis talked about embracing your users, and the need for evangelists to spread your message through organic traffic (&amp;#8220;web 2.0 aka labor 2.0&amp;#8221;). He encouraged audience members to go above and beyond when interacting with their users. Make their experience memorable, weird, fascinating, amazing, much like Zappos overdelivering (literally) on their shipping. Alexis also stressed that you need to be down-to-earth &amp;mdash; &amp;#8220;you don&amp;#8217;t need to be naturally charismatic, just don&amp;#8217;t be a dick. Be root-for-able&amp;#8221; &amp;mdash; both in your dealing with your users as well as with your cofounders. Most of all, do something you love.&lt;/p&gt;
&lt;p&gt;3. &lt;a href="http://www.mit.edu/people/zolot/home.html"&gt;Ken Zolot&lt;/a&gt; of &lt;span class="caps"&gt;MIT&lt;/span&gt;. Ken is the founder of &lt;a href="http://entrepreneurship.mit.edu/"&gt;MIT&amp;#8217;s Innovations Teams&lt;/a&gt; program. He talked briefly about what makes interesting technology the basis of a viable company or business, and how to make that transition. Ken also stressed the importance of good communication and having tangible results to show early on.&lt;/p&gt;
&lt;p&gt;4. Dan Theobald, &lt;a href="http://www.vecna.com"&gt;Vecna&lt;/a&gt;. As founder of a robots company, Dan&amp;#8217;s background was an interesting contrast to his largely web 2.0-centric peers at this event. He talked extensively about the social responsibility of a good company and incentivizing your employees. Dan is also strongly opposed to over-use of venture capital, and advised the audience to only deal with it if absolutely necessary. &amp;#8220;Other peoples money makes you stupid,&amp;#8221; he quipped, &amp;#8220;avoid it at all possible&amp;#8221;. One of the most interesting passages from Dan&amp;#8217;s talk was about how Vecna profit shares with their employees and uses a &amp;#8220;peer to peer&amp;#8221; points system (employees give &amp;#8220;cookies&amp;#8221; to one another to reward those who are providing value) to determine distributions.&lt;/p&gt;
&lt;p&gt;5. Kyle Vogt, &lt;a href="http://www.justin.tv/"&gt;Justin.tv&lt;/a&gt; (a Y-Combinator company). Kyle&amp;#8217;s talk was centered around a list of &amp;#8220;productivity hacks&amp;#8221; but the most interesting portion of his talk was about how Justin.tv dealt with the failure of their original idea and, instead of giving up, used it as an opportunity to change direction and embrace a more mainstream approach to get to where they are today. Also, perhaps his most important advice: &amp;#8220;stick to dot-com [domain names]&amp;#8221;.&lt;/p&gt;
&lt;p&gt;6. &lt;a href="http://angusdavis.com/"&gt;Angus Davis&lt;/a&gt; of &lt;a href="http://tellme.com"&gt;Tellme&lt;/a&gt;. Angus, another enthusiastic speaker, related stories about Tellme&amp;#8217;s rise and eventual acquisition by Microsoft. He also talked about his experience as an angel investor. His talk gets points for best use of technology as he employed a text messaging feedback system so audience members could tell him which vignettes they wanted to hear more about.&lt;/p&gt;
&lt;p&gt;7. &lt;a href="http://www.generalcatalyst.com/team/hemant_taneja"&gt;Hemant Teneja&lt;/a&gt; of &lt;a href="http://www.generalcataylst.com"&gt;General Catalyst Partners&lt;/a&gt;. Hemant, a venture capitalist with GC, talked not only about what GC looks for in prospective portfolio companies but also about what founders should look for in a VC, term sheets, and so on. An advocate of bootstrapping (is this rare for a VC?), he agreed with previous speakers that you should delay looking for VC unless you really need it, and make sure you&amp;#8217;ve created something demonstrable and have a viable business strategy before you make that decision. What gets GC excited? Brilliant founders, solving &amp;#8220;very hard&amp;#8221; problems, addressing large markets, and being ahead of the curve.&lt;/p&gt;
&lt;p&gt;8. Dharmesh Shah, &lt;a href="http://www.hubspot.com/"&gt;Hubspot&lt;/a&gt; (and author of the popular &lt;a href="http://onstartups.com/"&gt;On Startups&lt;/a&gt; blog). Dharmesh apologized to the crowd at least once for not being a professional speaker, but this seemed largely unnecessary as he had one of the more polished presentations of the day (although he did run through it a bit fast!) His talk was basically a &amp;#8220;marketing 101&amp;#8221; for early stage founders. &amp;#8220;How do you get customers with $0 budget?&amp;#8221; he asked. The answer is through inbound, not outbound, marketing; building the best experience for those who are already looking for you or the products you offer through mechanisms like search engine optimization. &amp;#8220;Make marketing about creativity, not cash&amp;#8221; he counseled.&lt;/p&gt;
&lt;p&gt;9. &lt;a href="http://en.wikipedia.org/wiki/Robin_Chase"&gt;Robin Chase&lt;/a&gt; of &lt;a href="http://zipcar.com"&gt;Zipcar&lt;/a&gt; / &lt;a href="http://www.goloco.org"&gt;GoLoco&lt;/a&gt;. Robin talked candidly about the origin and growth of Zipcar, sustainability, and the challenges that are facing the world and environment, and how &amp;#8220;doing good&amp;#8221; can be a foundation for business opportunities, too. On the topic of inspiration vs execution she says that &amp;#8220;execution is everything&amp;#8221; and advised audience members to get started today, by building the absolute smallest thing that they can to start with. Luck is important, too, she admitted, and noted that luck happens when &amp;#8220;preparation meets opportunity&amp;#8221;. Be prepared!&lt;/p&gt;
&lt;p&gt;10. &lt;a href="http://en.wikipedia.org/wiki/Dan_Bricklin"&gt;Dan Bricklin&lt;/a&gt;, VisiCalc. Dan is an entrepreneur, programmer, and author. He created the first electronic spreadsheet application in 1979 and has been innovating ever since. Dan&amp;#8217;s talk was a fast moving flurry of images from the early days, growth, and acquisition of VisiCalc and his company, Software Arts, and his experiences &amp;mdash; both good and bad &amp;mdash; as &amp;#8220;an entrepreneur 30 years later&amp;#8221;. His talk was refreshing and filled with humor. &amp;#8220;You will live through things you do not expect&amp;#8221;, Dan said as he was wrapping up.&lt;/p&gt;
&lt;p&gt;11. &lt;A href="http://en.wikipedia.org/wiki/Aaron_Swartz"&gt;Aaron Schwartz&lt;/a&gt; of Infogami / Reddit (a Y-Combinator company). At 14, Aaron co-authored the original &lt;span class="caps"&gt;RSS&lt;/span&gt; 1.0 specification, and has been active in the technology, entrepreneurial, and political action communities ever since. As part of the first Y-Combinator program, his company was eventually merged with Ohanian&amp;#8217;s Redit. He talked about launching a startup and joked about what to not do (&amp;#8220;the hollywood launch&amp;#8221;) and what might be a better strategy (&amp;#8220;the gmail launch&amp;#8221;, incremental features and invitations).&lt;/p&gt;
&lt;p&gt;12. Drew Houston, &lt;a href="http://www.getdropbox.com/"&gt;Dropbox&lt;/a&gt; (a Y-Combinator company). Drew&amp;#8217;s startup, Dropbox, is now serving over 2.5 million users. Drew talked about his personal experiences from the creation of Dropbox to growing it to this point, and the challenges he faced along the way. He championed engineering-centric organizations and noted that &amp;#8220;it&amp;#8217;s much easier for engineers to pick up the business side than for business people to pick up the engineering side&amp;#8221;. He also counseled the audience to &amp;#8220;get in over their heads&amp;#8221; and out of their comfort zones to learn things. Having friends in startups is tremendously helpful too; surround yourself with kindred spirits (which is why programs like Y-Combinator work so well).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Remote Pair Programming Resources</title>
   <link href="http://blog.zerosum.org/2009/9/15/remote-pair-programming-resources.html" />
   <published>2009-09-15T00:00:00-04:00</published>
   <updated>2009-09-15T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/9/15/remote-pair-programming-resources</id>
   <content type="html">&lt;p&gt;I usually don&amp;#8217;t double-post or call out the articles I write for &lt;a href="http://dobbscodetalk.com"&gt;&lt;span class="caps"&gt;DDJ&lt;/span&gt; Code Talk&lt;/a&gt; too much here (links are in the sidebar), but I wanted to make sure that &lt;a href="http://dobbscodetalk.com/index.php?option=com_myblog&amp;show=Remote-Pair-Programming-Resource.html&amp;Itemid=29"&gt;this one&lt;/a&gt; got noticed.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve had the good fortune lately to be working with a client who really appreciates the power of pair programming (something I&amp;#8217;ve been admittedly a bit slow to embrace in my role as a freelancer). Since I&amp;#8217;m only on-site with their team 2 days a week, I&amp;#8217;ve been forced to learn a fair bit about what&amp;#8217;s available for remote pairing tools.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s the short summary: &lt;a href="http://www.gnu.org/software/screen/"&gt;Screen&lt;/a&gt; + &lt;a href="http://www.vim.org/"&gt;Vim&lt;/a&gt; + &lt;a href="http://skype.com"&gt;Skype&lt;/a&gt; is a recipe for awesome. Read the &lt;a href="http://dobbscodetalk.com/index.php?option=com_myblog&amp;show=Remote-Pair-Programming-Resource.html&amp;Itemid=29"&gt;full article&lt;/a&gt; if you want to find out about other options.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rumble Results</title>
   <link href="http://blog.zerosum.org/2009/9/3/rumble-results-2.html" />
   <published>2009-09-03T00:00:00-04:00</published>
   <updated>2009-09-03T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/9/3/rumble-results-2</id>
   <content type="html">&lt;p&gt;The &lt;a href="http://blog.railsrumble.com/2009/8/30/and-the-winner-is"&gt;results&lt;/a&gt; are in for the &lt;a href="http://r09.railsrumble.com"&gt;2009 Rails Rumble&lt;/a&gt;. Check em out and peep the winners. Some pretty impressive stuff for a single 48-hour sprint, right? Right!&lt;/p&gt;
&lt;p&gt;I&amp;#8217;d like to personally thank all the &lt;a href="http://blog.railsrumble.com/sponsors"&gt;sponsors&lt;/a&gt;, &lt;a href="http://blog.railsrumble.com/judges/expert-panel"&gt;expert panelists&lt;/a&gt;, and especially the &lt;a href="http://r09.railsrumble.com/teams"&gt;contestants&lt;/a&gt; that made this years contest the best one yet. We&amp;#8217;re looking forward to using the feedback we&amp;#8217;ve received this year to make the next one even better, and starting to seriously discuss doing some more language/framework-agnostic events too.&lt;/p&gt;
&lt;p&gt;But first, we need a little bit of a break :). Some downtime next weekend sure will be nice!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rumble Build Weekend</title>
   <link href="http://blog.zerosum.org/2009/8/22/rumble-build-weekend.html" />
   <published>2009-08-22T00:00:00-04:00</published>
   <updated>2009-08-22T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/8/22/rumble-build-weekend</id>
   <content type="html">&lt;p&gt;This weekend is &lt;a href="http://search.twitter.com/search?q=railsrumble"&gt;Rails Rumble Build Weekend&lt;/a&gt;, which means that over 200 teams of 1-4 people are, at this very moment, working diligently (tirelessly!) to build the next &lt;a href="http://tastyplanner.com"&gt;awesome&lt;/a&gt; &lt;a href="http://meetinbetween.us"&gt;48-hour&lt;/a&gt; &lt;a href="http://qflip.net"&gt;micro-app&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is the third year in a row we&amp;#8217;ve run the contest and things seem to be going smoother than ever. Well, so far. Big thanks to &lt;a href="http://twtter.com/Sutto"&gt;Darcy Laycock&lt;/a&gt;, &lt;a href="http://twitter.com/erinshine"&gt;Erin Shine&lt;/a&gt;, and &lt;a href="http://neverlet.be"&gt;Jeff Rafter&lt;/a&gt; for being incredible co-conspirators, to all our competition &lt;a href="http://blog.railsrumble.com/sponsors"&gt;sponsors&lt;/a&gt;, and especially to the participants who are really pouring their everything into this. I can&amp;#8217;t wait to see how some of these ideas turn out.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.zerosum.org/assets/2009/7/7/rr09_badge_125.png" alt="Rails Rumble" style="float:right; padding: 5px 0 10px 10px"/&gt;&lt;/p&gt;
&lt;p&gt;In case you&amp;#8217;re curious, we&amp;#8217;re running the voting process a little bit differently this year, and have assembled a fine panel of &lt;a href="http://blog.railsrumble.com/judges/expert-panel"&gt;expert judges&lt;/a&gt; to help qualify the best of the best before they go on to public voting. These people come from all corners of the web startup ecosystem and I&amp;#8217;m really amazed that most of them were able to find the time in their busy schedules to help us out &amp;mdash; we&amp;#8217;re honored! So a big thanks to them, too.&lt;/p&gt;
&lt;p&gt;The competition wraps tomorrow (Sunday) night at midnight &lt;span class="caps"&gt;UTC&lt;/span&gt;, and then the expert panelists have a couple days to work their magic. Public voting should probably open on Thursday if all goes to schedule. If you&amp;#8217;re not competing you can still &lt;a href="http://r09.railsrumble.com/login"&gt;register for an account&lt;/a&gt; and help us judge! For more information, head on over to the &lt;a href="http://r09.railsrumble.com"&gt;competition site&lt;/a&gt; or check out the &lt;a href="http://blog.railsrumble.com"&gt;blog&lt;/a&gt;. Make sure to subscribe for updates. Thanks!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Testing ActiveRecord Observers</title>
   <link href="http://blog.zerosum.org/2009/7/25/testing-activerecord-observers.html" />
   <published>2009-07-25T00:00:00-04:00</published>
   <updated>2009-07-25T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/7/25/testing-activerecord-observers</id>
   <content type="html">&lt;p&gt;Need to unit test those pesky ActiveRecord observers you&amp;#8217;re using? I don&amp;#8217;t use em often, but there are times when they&amp;#8217;re definitely useful. Fortunately, since &lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/Observer.html"&gt;AR::Observer&lt;/a&gt; leverages Ruby&amp;#8217;s &lt;a href="http://ruby-doc.org/core/classes/Observable.html"&gt;Observable&lt;/a&gt; module all you have to do is call &lt;tt&gt;MyModel.delete_observers&lt;/tt&gt; in your test setup or &lt;code&gt;before&lt;/code&gt; block.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ZombieSighting.delete_observers&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Better yet, add the exclusions to your test or spec helper file. Then you can unit test your models comfortably in isolation, and write tests for your observers that look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;describe Observer
  before(:each) do
    @obs = ZombieSightingObserver.instance
    @thing = Factory.build(:zombie_sighting)
  end

  it 'should generate a new notification' do
    lambda { 
      @obs.after_create(@thing)
    }.should change(Notification, :count)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We wouldn&amp;#8217;t want to couple zombie sightings too tightly with notifications, after all, as that might anger them even further (zombies are known to be crazy about &lt;a href="http://en.wikipedia.org/wiki/Single_responsibility_principle"&gt;&lt;span class="caps"&gt;SRP&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rails Camp New England</title>
   <link href="http://blog.zerosum.org/2009/7/22/rails-camp-new-england.html" />
   <published>2009-07-22T00:00:00-04:00</published>
   <updated>2009-07-22T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/7/22/rails-camp-new-england</id>
   <content type="html">&lt;p&gt;Last Friday, about 30 people descended on a large house in Bryant Pond, Maine for &lt;a href="http://railscamps.com"&gt;Rails Camp&lt;/a&gt; New England. Organizer &lt;a href="http://freelancing-gods.com"&gt;Pat Allan&lt;/a&gt; has been running Rails Camp events in the UK and his home nation of Australia for quite some time, but this was the very first North American event (co-organized by Boston.rb&amp;#8217;s own &lt;a href="http://cardarella.blogspot.com"&gt;Brian Cardarella&lt;/a&gt;). Personally, I think it was a smashing success and I&amp;#8217;m really glad I had the chance to be a part of it.&lt;/p&gt;
&lt;p&gt;Our &lt;a href="http://picasaweb.google.com/tedroche/RailscampNorthEast2009#"&gt;weekend retreat&lt;/a&gt; basically consisted of group hacking and pair programming, lots of lively discussions, gaming, and plenty of R&amp;amp;R. Frisbee was played. Food was eaten. Canoes were canoed. &lt;a href="http://www.urbanterror.net"&gt;Urban Terror&lt;/a&gt; was instigated. Werewolves were slain by lakeside campfire light. Alcohol was consumed. In no particular order, of course.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.zerosum.org/assets/2009/7/22/yield.png" alt="Rails Camp" style="float: right; margin: 0 0 10px 10px;"/&gt;&lt;/p&gt;
&lt;p&gt;In addition to the ever-important extra-curriculars, we had time to work on personal projects and share with others through a series of BarCamp-style sessions. These sessions included topics as diverse as Ruby Gems, &lt;a href="http://gemcutter.org"&gt;GemCutter&lt;/a&gt;, Internationalization, &lt;a href="http://couchdb.apache.org"&gt;CouchDB&lt;/a&gt;, and &lt;a href="http://radiantcms.org"&gt;RadiantCMS&lt;/a&gt;. There were also a number of app demos and lots of peer consulting and mentoring going on. Experience levels ranged from complete beginners to seasoned professionals, but all egos were checked at the door and everyone seemed to get along like old friends. Social games and sessions really helped people get to know one another, and keeping the event small meant that by the time you left, everyone was on a first-name basis.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m not sure how (cough) &lt;strong&gt;productive&lt;/strong&gt; I was over the course of the weekend, but I sure had a great time, met a lot of interesting people, and learned a lot from them. If you&amp;#8217;ve never attended anything like this I strongly encourage you to. It&amp;#8217;s a great mix of learning and fun, and the freestyle format allows you to make of it what you want. A far better experience than any conference I&amp;#8217;ve attended in the past year, imo, and far less costly at a mere $120 for the entire weekend, including all lodging and food.&lt;/p&gt;
&lt;p&gt;A big thanks to Pat and Brian for all their hard work, to &lt;a href="http://thoughtbot.com"&gt;Thoughtbot&lt;/a&gt; and &lt;a href="http://zendesk.com"&gt;ZenDesk&lt;/a&gt; for sponsoring, and to everyone else that showed up for being full of awesome. Hopefully we&amp;#8217;ll do another RC New England event soon. I&amp;#8217;m thinking that a mid-winter ski lodge excursion sounds like a damn good idea&amp;#8230; Yeh?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>TwitterAuth Integration Testing</title>
   <link href="http://blog.zerosum.org/2009/7/13/twitter-auth-integration-testing.html" />
   <published>2009-07-13T00:00:00-04:00</published>
   <updated>2009-07-13T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/7/13/twitter-auth-integration-testing</id>
   <content type="html">&lt;p&gt;Michael Bleigh&amp;#8217;s &lt;a href="http://github.com/mbleigh/twitter-auth"&gt;TwitterAuth gem&lt;/a&gt; is truly full of awesome. It&amp;#8217;s a complete OAuth authentication and &lt;span class="caps"&gt;API&lt;/span&gt; access solution for building Twitter apps with Rails. It uses familiar conventions borrowed from the Restful Authentication plugin, too. If you&amp;#8217;re building a Rails-based app and you want to allow your users to &lt;a href="http://apiwiki.twitter.com/Sign-in-with-Twitter"&gt;Sign in with Twitter&lt;/a&gt; there&amp;#8217;s just no better way to go.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.zerosum.org/assets/2009/7/13/twitter-bird.gif" alt="TwitterAuth" style="float:right; margin: 0 0 10px 10px;" /&gt;&lt;/p&gt;
&lt;p&gt;For this particular app, I&amp;#8217;m using the dynamic duo of &lt;a href="http://cukes.info"&gt;Cucumber&lt;/a&gt; and &lt;a href="http://github.com/brynary/webrat"&gt;Webrat&lt;/a&gt; to whip up integration tests. Since I initially stumbled a little bit when thinking about how to test integrated authentication against an external source like Twitter, I thought I&amp;#8217;d doc the solution here in case other people were having the same issue.&lt;/p&gt;
&lt;p&gt;Ready? Let&amp;#8217;s do it.&lt;/p&gt;
&lt;h3&gt;Setup&lt;/h3&gt;
&lt;p&gt;First, install the TwitterAuth gem and use the provided generator to whip up the appropriate facilities. You&amp;#8217;ll need to &lt;a href="http://twitter.com/apps"&gt;register your Twitter application accounts&lt;/a&gt; too. Or you know what? Screw it. If you want to make this super easy on yourself, Mike wrote a really great &lt;a href="http://github.com/mbleigh/rails-templates/blob/e9b9f3efebca6d519fa75f029fe899798d7e369d/twitterapp.rb"&gt;Twitter app Rails template&lt;/a&gt; that does all the setup for you, including walking you through getting the dev accounts. It&amp;#8217;s nice, try it out. You&amp;#8217;ll be up and writing Twitter apps in no time.&lt;/p&gt;
&lt;p&gt;For the rest of this I&amp;#8217;m going to assume that you have all of that working, and have installed Cucumber too. Don&amp;#8217;t have Cucumber? Install it using RubyGems and then just run &lt;code&gt;script/generate cucumber&lt;/code&gt; inside your Rails app.&lt;/p&gt;
&lt;h3&gt;Authentication Feature&lt;/h3&gt;
&lt;p&gt;So let&amp;#8217;s write a Cucumber feature to test authentication in our boilerplate Twitter template application. Put the following in &lt;code&gt;features/authentication.feature&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Feature: Authentication
In order to create and edit games
As a user
I want to sign in with Twitter

  Scenario: Login via Twitter
    When I go to "the homepage"
    And I follow "Login via Twitter"
    And Twitter authorizes me
    Then I should see "Logged in as"

  Scenario: Checking login status
    Given I am signed in
    When I go to "the homepage"
    Then I should see "Logged in as"

  Scenario: Log out
    Given I am signed in
    When I go to "the homepage"
    And I follow "Log out"
    Then I should see "Login via Twitter"
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step Definitions&lt;/h3&gt;
&lt;p&gt;Next, you&amp;#8217;ll need to write step definitions to satisfy the missing steps. Do that by creating a file called &lt;code&gt;features/step_definitions/auth_steps.rb&lt;/code&gt;. The content of the file should define the following two steps:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Given /^I am signed in$/ do  
  visit login_path
  visit oauth_callback_path
end  

When /^Twitter authorizes me$/ do
  visit oauth_callback_path
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Fake Style&lt;/h3&gt;
&lt;p&gt;The secret sauce here is &lt;a href="http://github.com/chrisk/fakeweb"&gt;FakeWeb&lt;/a&gt;. We&amp;#8217;ll use it to fake out responses from the Twitter auth service so that your integration tests stay local (and reliable). Make sure to &lt;code&gt;gem install fakeweb&lt;/code&gt;, and add the following to &lt;code&gt;tests/environments/cucumber.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;config.gem "fakeweb", :version =&amp;gt; "&amp;gt;= 1.2.5"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now edit Cucumber&amp;#8217;s &lt;code&gt;features/support/env.rb&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FakeWeb.allow_net_connect = false
FakeWeb.register_uri(:post, 'http://twitter.com/oauth/request_token', :body =&amp;gt; 'oauth_token=fake&amp;amp;oauth_token_secret=fake')
FakeWeb.register_uri(:post, 'http://twitter.com/oauth/access_token', :body =&amp;gt; 'oauth_token=fake&amp;amp;oauth_token_secret=fake')
FakeWeb.register_uri(:get, 'http://twitter.com/account/verify_credentials.json', :response =&amp;gt; File.join(RAILS_ROOT, 'features', 'fixtures', 'verify_credentials.json'))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we&amp;#8217;re stubbing out the interaction with Twitter auth, and responding to all outbound authorization attempts with canned data. Note that this references a fixture file, containing a sample &lt;code&gt;verify_credentials&lt;/code&gt; &lt;span class="caps"&gt;API&lt;/span&gt; response from Twitter. You can obtain a copy using curl from the comfort of your terminal prompt (substitute your own username and password):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -i -u user:pass "http://twitter.com/account/verify_credentials.json" &amp;gt; verify_credentials.json&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last thing you&amp;#8217;ll want to do is to check your &lt;code&gt;twitter_auth.yml&lt;/code&gt; file and make sure there&amp;#8217;s a &lt;code&gt;cucumber&lt;/code&gt; environment defined in it. If not, you may need to add it.&lt;/p&gt;
&lt;h3&gt;And We&amp;#8217;re Done&lt;/h3&gt;
&lt;p&gt;Alright that should do it. Go ahead and run &lt;code&gt;rake features&lt;/code&gt;. Everything should be green. And green is good. If you need to write other features that are dependent on a login requirement, you can reuse the same &lt;em&gt;&amp;#8220;Given I am signed in&amp;#8221;&lt;/em&gt; step that we created earlier.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href="http://bkocik.net/2009/05/07/testing-twitter-oauth-with-cucumber-webrat-and-fakeweb/"&gt;b.kocik&lt;/a&gt;, whose original post on using FakeWeb to stub Twitter auth was 80% of the solution I needed here.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rumble Time</title>
   <link href="http://blog.zerosum.org/2009/7/7/rumble-time.html" />
   <published>2009-07-07T00:00:00-04:00</published>
   <updated>2009-07-07T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/7/7/rumble-time</id>
   <content type="html">&lt;p&gt;We opened registration for the &lt;a href="http://r09.railsrumble.com"&gt;2009 Rails Rumble&lt;/a&gt; yesterday. This is the third year in a row that we&amp;#8217;re running the contest and it&amp;#8217;s sure to be the best one yet. The build weekend is August 22nd-23rd but you need to register this week if you want a seat. If I were you, I&amp;#8217;d go register now before it fills up ;-). &lt;img src="http://blog.zerosum.org/assets/2009/7/7/rr09_badge_125.png" alt="Rails Rumble 2009" style="float: right; margin: 0 0 10px 10px;"/&gt;&lt;/p&gt;
&lt;p&gt;In other news, I&amp;#8217;ll be presenting at the second &lt;a href="http://www.pecha-kucha.org/cities/portsmouth-nh/2"&gt;Portsmouth Pecha-Kucha Night&lt;/a&gt; tomorrow, July 8th. I&amp;#8217;ll actually be talking about the creative power of constraints, and describing our experiences organizing the Rumble will be a big part of that. If you&amp;#8217;re in town, make sure to check it out. I&amp;#8217;ve never done a p-k talk before but it sounds like it&amp;#8217;s going to be a lot of fun.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>The Way They Were Inside</title>
   <link href="http://blog.zerosum.org/2009/6/23/the-way-they-were-inside.html" />
   <published>2009-06-23T00:00:00-04:00</published>
   <updated>2009-06-23T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/6/23/the-way-they-were-inside</id>
   <content type="html">&lt;p&gt;Last night we headed to Londonderry NH to view our submission to the 2009 &lt;a href="http://www.48hourfilm.com/"&gt;48 Hour Film Project&lt;/a&gt; on the big screen alongside all the other &lt;a href="http://www.48hourfilm.com/newhampshire"&gt;New Hampshire submissions&lt;/a&gt;. In case you haven&amp;#8217;t been following my &lt;a href="http://zapnap.tumblr.com"&gt;tumblr&lt;/a&gt; (where I tend to post less techie things), I thought I&amp;#8217;d double-post it here for your viewing pleasure:&lt;/p&gt;
&lt;p&gt;&lt;object width="425" height="344"&gt;&lt;br /&gt;
&lt;param name="movie" value="http://www.youtube.com/v/_H_xO9xoBJc&amp;hl=en&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;br /&gt;
&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;br /&gt;
&lt;embed src="http://www.youtube.com/v/_H_xO9xoBJc&amp;hl=en&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;br /&gt;
&lt;/object&gt;&lt;/p&gt;
&lt;p&gt;For those of you that don&amp;#8217;t know, the 48HFP is a filmmaking challenge to write, shoot, and edit a short 5-7 minute film in a weekend. It was also probably the biggest single influence in our putting together the &lt;a href="http://railsrumble.com"&gt;Rails Rumble&lt;/a&gt;, which follows a similar model but is geared towards web development and tech startup bootstrapping.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;d been a couple of years since I last participated in the project (when I was living in Boston, attempting to make bad sci-fi movies). This time around &lt;a href="http://johnherman.org"&gt;John Herman&lt;/a&gt;, our director, ran the project like a sea captain leading a battleship to war. It really demonstrated, to me, the power of having a consistent vision and the right people lined up to do the right jobs ahead of time. Although I&amp;#8217;m a little bummed that I missed out on being part of the crew due to prior obligations this year, being on the brainstorming / writing team was a great experience, and I probably would have just gotten in the way during production anyway ;-).&lt;/p&gt;
&lt;p&gt;In filmmaking as with development, constraints are a powerful thing, and the 48HFP is a real showcase of this. It also demonstrates that many of the fundamentals of the &lt;a href="http://gettingreal.37signals.com/"&gt;&amp;quot;Getting Real&amp;quot;&lt;/a&gt; philosophy can be applied equally well to all sorts of art forms and mediums. IE, don&amp;#8217;t let time limitations or overcommitted schedules stop you from showing off your bountiful awesome.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;ve got a few minutes, check out &lt;a href="http://48.tv"&gt;www.48.tv&lt;/a&gt;, where you can watch a bunch of other 48HFP films &amp;#8212; I think you&amp;#8217;ll be impressed by the creativity in a lot of them, not to mention the production values they achieved under duress. Props to &lt;a href="http://twitter.com/johnherman"&gt;John&lt;/a&gt;, &lt;a href="http://twitter.com/danfruend"&gt;Dan Freund&lt;/a&gt;, &lt;a href="http://twitter.com/ryanplaisted"&gt;Ryan Plaisted&lt;/a&gt;, &lt;a href="http://twitter.com/bodhipaksa"&gt;Bodhipaksa&lt;/a&gt;, and everyone else who was involved. And thanks for letting me tag along.&lt;/p&gt;
&lt;p&gt;Winners of the NH competition will be announced at the upcoming &amp;#8220;Best of NH&amp;#8221; screening, and the winner of that will move on to compete in &lt;a href="http://www.48hourfilm.com/filmapalooza/"&gt;Filmapalooza&lt;/a&gt; at &lt;span class="caps"&gt;NAB&lt;/span&gt; Las Vegas 2010. Many of the other films we saw last night were pretty incredible, including entries from local filmmakers like &lt;a href="http://twitter.com/marcdole"&gt;Marc Dole&lt;/a&gt; and &lt;a href="http://twitter.com/BaldGuyClimate"&gt;Bill Rogers&lt;/a&gt;, so I&amp;#8217;m not holding my breath just yet, but it certainly would be cool. Either way, the best part of these things isn&amp;#8217;t winning, but rather seeing what you can do, and watching other people bring their A-game too. It&amp;#8217;s inspiring.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Serious Bizness</title>
   <link href="http://blog.zerosum.org/2009/6/1/ruby-developer-for-hire.html" />
   <published>2009-06-01T00:00:00-04:00</published>
   <updated>2009-06-01T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/6/1/ruby-developer-for-hire</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m currently available for consulting work. I took a bit of time off for some personal projects and a much-needed spring vacation and now I&amp;#8217;m once again ready to dive into an interesting client / startup project. Are you looking for a motivated, opinionated, yet thoughtful Ruby developer who enjoys mountain biking, foreign cinema, and long walks on the beach?&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Web Development&lt;/strong&gt;: My core expertise is end-to-end web application development for Ruby, Rails, or Sinatra projects &amp;#8211; If you&amp;#8217;re looking for a project lead or a team to build your next big web application, I can help. Or if you need an additional hand to augment the development speed or best practices of your existing team, I&amp;#8217;m happy to do that too.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Code Reviews&lt;/strong&gt;: Concerned about the quality of your codebase or maybe just looking to get an outside perspective? Reviews include analysis of your code organization and structure, test coverage and effectiveness, and overall complexity / runtime efficiency.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition to the Ruby skill set, I&amp;#8217;m also well-versed in JavaScript, Flash/ActionScript, social media tools, and the other standard systems and services that the web is built on. If you&amp;#8217;ve read this blog and browsed my &lt;a href="http://github.com/zapnap"&gt;&lt;span class="caps"&gt;OSS&lt;/span&gt; project contributions&lt;/a&gt;, you already know that I&amp;#8217;m passionate about technology, embrace web standards, and thoroughly enjoy working on innovative new ideas. I&amp;#8217;ve also read a lot of comic books, and listen to all sorts of weird music, in case that helps.&lt;/p&gt;
&lt;p&gt;I can provide references and an expanded portfolio by request; a rather smallish selection of work samples is currently visible on my &lt;a href="http://nthmetal.com"&gt;freelance business micro-site&lt;/a&gt;. If you&amp;#8217;re interested, you can get in touch via email (nap at zerosum dot org) or contact me on &lt;a href="http://twitter.com/zapnap"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>GitHub has an Apps Platform</title>
   <link href="http://blog.zerosum.org/2009/5/14/github-has-an-apps-platform.html" />
   <published>2009-05-14T00:00:00-04:00</published>
   <updated>2009-05-14T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/5/14/github-has-an-apps-platform</id>
   <content type="html">&lt;p&gt;After I pooped out the initial version of &lt;a href="http://rdoc.info"&gt;rdoc.info&lt;/a&gt; a week or two ago, &lt;a href="http://neverlet.be"&gt;Jeff&lt;/a&gt; and I were bullshitting about the kind of stuff we could add to it when he had a bit of an epiphany: &amp;#8220;the place for documentation about GitHub projects is on GitHub&amp;#8221;. Yes! Of course! Why didn&amp;#8217;t we think of that before?&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.zerosum.org/assets/2009/5/14/octocat_professor.png" width="232" height="208" style="float: right; padding: 5px 5px 10px 10px;"/&gt;&lt;/p&gt;
&lt;p&gt;So we registered the &lt;a href="http://docs.github.com"&gt;&amp;#8220;docs&amp;#8221;&lt;/a&gt; user on GitHub and went about building an extension to rdoc.info based on the GitHub pages platform. As of now, when you enter a project on rdoc.info, it&amp;#8217;ll build docs for them locally and also generate a GitHub-themed set and push them to the docs user account pages on GitHub. In fact, you never even have to visit rdoc.info if you don&amp;#8217;t want to (although project documentation will continue to be available there). For an example, see &lt;a href="http://docs.github.com/jnunemaker/httparty"&gt;Nunemaker&amp;#8217;s HTTParty &lt;span class="caps"&gt;API&lt;/span&gt; Docs&lt;/a&gt;. Make sure to play with the methods and namespaces buttons in the header.&lt;/p&gt;
&lt;p&gt;As far as I know, we&amp;#8217;re the first ones to use GitHub pages as an actual &amp;#8220;app platform&amp;#8221;, which makes me kind of giddy. You can &lt;a href="http://neverlet.be/2009/5/14/github-has-an-apps-platform"&gt;read more about what we did and how we did it&lt;/a&gt; over on Jeff&amp;#8217;s blog. He deserves most of the credit for this one, including that awesome GitHub &lt;span class="caps"&gt;YARD&lt;/span&gt; theme and more than a fair bit of tricksy JavaScript goodness. Of course, GitHub deserves a lot of credit too, for building an awesome and extensible service. If you run into any issues with the docs stuff (which is still kinda experimental), please report them via the &lt;a href="http://github.com/docs/docs.github.com"&gt;GitHub project&lt;/a&gt;. Thanks!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Railsconf 2009 Recap</title>
   <link href="http://blog.zerosum.org/2009/5/13/railsconf-recap.html" />
   <published>2009-05-13T00:00:00-04:00</published>
   <updated>2009-05-13T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/5/13/railsconf-recap</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m writing this from a cramped airline seat as we jet back from Las Vegas to balmy Manchester, NH (wifi on planes is awesome &amp;#8212; thanks Southwest). Amanda and I spent a week in Vegas during which I attended &lt;a href="http://railsconf.com"&gt;Railsconf 2009&lt;/a&gt; and caught a couple of pretty &lt;a href="http://www.mgmgrand.com/ka/default.aspx"&gt;incredible&lt;/a&gt; &lt;a href="http://www.mgmgrand.com/entertainment/crazy-horse-show.aspx"&gt;shows&lt;/a&gt;. Then we road tripped it out to the Grand Canyon in Arizona and hiked in below the rim. Which was absolutely breathtaking. I wish we could have spent more time there and less in the city, to be honest.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.zerosum.org/assets/2009/5/13/railsconf.png" height="85" width="183" style="float: right; padding: 5px 5px 5px 10px"/&gt;&lt;/p&gt;
&lt;p&gt;Anyway, the conference itself had both its high and low points, but it was neither a total stinker nor an overwhelmingly fantastical experience this year. &lt;a href="http://www.petercooper.co.uk/"&gt;Peter Cooper&lt;/a&gt;, whom I had the pleasure of meeting there, has done a much better job than I of summarizing over at &lt;a href="http://www.rubyinside.com/the-mega-railsconf-2009-round-up-1757.html"&gt;RubyInside&lt;/a&gt;. Friends &lt;a href="http://www.culann.com/2009/05/railsconf-2009"&gt;Ben Scofield&lt;/a&gt; and &lt;a href="http://litanyagainstfear.com/"&gt;Nick Quaranto&lt;/a&gt; also have some great notes at their respective sites. In fact, I&amp;#8217;m going to steal Ben&amp;#8217;s format for this post.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;People&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The best part of a conference is the people and the conversations, and the afterhours activities. Or at least, that&amp;#8217;s been my experience thus far. This time around was no different. Greets to &lt;a href="http://twitter.com/bcardarella"&gt;bcardadella&lt;/a&gt;, &lt;a href="http://twitter.com/bphogan"&gt;bphogan&lt;/a&gt;, &lt;a href="http://twitter.com/brupm"&gt;brupm&lt;/a&gt;, &lt;a href="http://twitter.com/bryanl"&gt;bryanl&lt;/a&gt;, &lt;a href="http://twitter.com/bscofield"&gt;bscofield&lt;/a&gt;, &lt;a href="http://twitter.com/cdwarren"&gt;cdwarren&lt;/a&gt;, &lt;a href="http://twitter.com/croaky"&gt;croaky&lt;/a&gt;, &lt;a href="http://twitter.com/cwsaylor"&gt;cwsaylor&lt;/a&gt;, &lt;a href="http://twitter.com/danabrit"&gt;danabrit&lt;/a&gt;, &lt;a href="http://twitter.com/davidcjames"&gt;davidcjames&lt;/a&gt;, &lt;a href="http://twitter.com/defunkt"&gt;defunkt&lt;/a&gt;, &lt;a href="http://twitter.com/dpickett"&gt;dpickett&lt;/a&gt;, &lt;a href="http://twitter.com/erebor"&gt;erebor&lt;/a&gt;, &lt;a href="http://twitter.com/fowlduck"&gt;fowlduck&lt;/a&gt;, &lt;a href="http://twitter.com/greggpollack"&gt;greggpollack&lt;/a&gt;, &lt;a href="http://twitter.com/graysky"&gt;graysky&lt;/a&gt;, &lt;a href="http://twitter.com/jamesgolick"&gt;jamesgolick&lt;/a&gt;, &lt;a href="http://twitter.com/jeffrafter"&gt;jeffrafter&lt;/a&gt;, &lt;a href="http://twitter.com/jharuska"&gt;jharuska&lt;/a&gt;, &lt;a href="http://twitter.com/jimweirich"&gt;jimweirich&lt;/a&gt;, &lt;a href="http://twitter.com/joefiorini"&gt;joefiorini&lt;/a&gt;, &lt;a href="http://twitter.com/jnunemaker"&gt;jnunemaker&lt;/a&gt;, &lt;a href="http://twitter.com/jremsikjr"&gt;jremsikjr&lt;/a&gt;, &lt;a href="http://twitter.com/keavy"&gt;keavy&lt;/a&gt;, &lt;a href="http://twitter.com/knowtheory"&gt;knowtheory&lt;/a&gt;, &lt;a href="http://twitter.com/lazyatom"&gt;lazyatom&lt;/a&gt;, &lt;a href="http://twitter.com/linoj"&gt;linoj&lt;/a&gt;, &lt;a href="http://twitter.com/mbleigh"&gt;mbleigh&lt;/a&gt;, &lt;a href="http://twitter.com/mojombo"&gt;mojombo&lt;/a&gt;, &lt;a href="http://twitter.com/patmaddox"&gt;patmaddox&lt;/a&gt;, &lt;a href="http://twitter.com/peterc"&gt;peterc&lt;/a&gt;, &lt;a href="http://twitter.com/qrush"&gt;qrush&lt;/a&gt;, &lt;a href="http://twitter.com/rbates"&gt;rbates&lt;/a&gt;, &lt;a href="http://twitter.com/reinh"&gt;reinh&lt;/a&gt;, &lt;a href="http://twitter.com/robertdempsey"&gt;robertdempsey&lt;/a&gt;, &lt;a href="http://twitter.com/seanhussey"&gt;seanhussey&lt;/a&gt;, &lt;a href="http://twitter.com/Skizzles"&gt;skizzles&lt;/a&gt;, &lt;a href="http://twitter.com/solaredge"&gt;solaredge&lt;/a&gt;, &lt;a href="http://twitter.com/techpickles"&gt;techpickles&lt;/a&gt;, &lt;a href="http://twitter.com/wifelette"&gt;wifelette&lt;/a&gt;, &lt;a href="http://twitter.com/wycats"&gt;wycats&lt;/a&gt;, &lt;a href="http://twitter.com/zachinglis"&gt;zachinglis&lt;/a&gt; and anyone else whom I might have forgotten to add to the list (sorry!). Thanks guys.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sessions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The sessions this year were spotty, but generally I think the content was better than the previous Railsconf. I mistakingly sat through too many introductory talks and many others reported the same; everyone could benefit from session experience level labels. It&amp;#8217;s weird that the organizers don&amp;#8217;t do this, since they ask speakers about the experience level of their talks as part of the proposal process.&lt;/p&gt;
&lt;p&gt;In any case, a number of the talks I saw this year stood out as being particularly great:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Jason Rudolph and Larry Karnowski on &lt;a href="http://en.oreilly.com/rails2009/public/schedule/detail/8013"&gt;JavaScript integration testing&lt;/a&gt; (using the BlueRidge project)&lt;/li&gt;
	&lt;li&gt;Bryan Helmkamp&amp;#8217;s &lt;a href="http://en.oreilly.com/rails2009/public/schedule/detail/8554"&gt;Webrat&lt;/a&gt; talk&lt;/li&gt;
	&lt;li&gt;Michael Bleigh&amp;#8217;s &lt;a href="http://en.oreilly.com/rails2009/public/schedule/detail/8517"&gt;Twitter app development&lt;/a&gt; session&lt;/li&gt;
	&lt;li&gt;Blythe Dunham on her experiences &lt;a href="http://en.oreilly.com/rails2009/public/schedule/detail/7489"&gt;integrating &lt;span class="caps"&gt;SMS&lt;/span&gt; support&lt;/a&gt; into Rails apps&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There were a lot of talks this year about testing, cache control / optimization, and Rack / Rails Metal. As well as some useful Rails 3 speculation and discussion. All good stuff.&lt;/p&gt;
&lt;p&gt;Interestingly, I really didn&amp;#8217;t care for many of the (very rough) ideas expressed in Yehuda&amp;#8217;s &lt;a href="http://en.oreilly.com/rails2009/public/schedule/detail/7785"&gt;mountable Rails apps&lt;/a&gt; (Rails 3) session &amp;#8212; in particular I really had no clue why they kept comparing Rails (a framework) to Drupal (a &lt;span class="caps"&gt;CMS&lt;/span&gt;). But, that said, the talk did do a great job stimulating discussion about alternative approaches in &amp;#8220;CabooseConf&amp;#8221; &amp;#8212; apparently just a small room with, uh, tables and stuff &amp;#8212; between myself, Bryan, Josh, Ted and others. For this reason it definitely belongs in my favorite sessions list.&lt;/p&gt;
&lt;p&gt;[mountable app slices] are a challenging problem, and there are a lot of issues in terms of sharing application state, resolving cross-app dependencies, and so on. I hope that we&amp;#8217;ll have an elegant solution to this soon; but I suspect that the real answer may be in making component-sized micro-apps easier to mount and integrate rather than taking an &amp;#8220;app slices&amp;#8221; or engines approach (if the latter case prevails, the Radiant extensions system has some stuff we can learn from).&lt;/p&gt;
&lt;p&gt;The keynotes were mixed also&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;The opening &lt;span class="caps"&gt;DHH&lt;/span&gt; keynote teased us with some interesting Rails 3 info but also repeated a lot of mantras we&amp;#8217;d heard before with the usual rallying cries&lt;/li&gt;
	&lt;li&gt;The &amp;#8220;fireside chat&amp;#8221; with Tim Ferriss was a bit of a disaster; although I think there were at least a few interesting nuggets in there somewhere&lt;/li&gt;
	&lt;li&gt;Chris Wanstrath&amp;#8217;s &amp;#8220;how to be a famous Rails developer&amp;#8221; essay was a definite highlight; well written and thought-provoking, it should be a wakeup call to those people in the community who put personal ego before productivity and creativity&lt;/li&gt;
	&lt;li&gt;Uncle Bob was full of energy and was no doubt entertaining, but to be honest, the content was blah to say the least. More repetition of the same rah-rah we&amp;#8217;ve had drilled into our heads for eons, without anything new. A little disappointed but almost everyone else seemed to love it&lt;/li&gt;
	&lt;li&gt;The closing Rails core panel&amp;#8230; to be honest, I skipped it. I hear it went well, though&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;The Rails Rumble Panel&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Speaking of panels, I think our own &lt;a href="http://en.oreilly.com/rails2009/public/schedule/detail/7765"&gt;Rails Rumble / productivity panel&lt;/a&gt; went fairly well, although it was missing much of the energy present in our pre-panel planning conversations, which was really a shame. It&amp;#8217;s doing decent in the ratings but not stellar, hovering around a 3/5. As Ben (one of our panelists) notes on his own blog, the panel format can be a difficult one to get a lot out of, and I definitely felt this myself sitting through other panels last week. However, I think the Rumble panelists did a damn good job discussing the merits of innovation competitions and relaying advice about finding teammates / cofounders, translating their entries into marketable web properties, and noting the tips, tools, and techniques that helped them excel in a severely constrained timeframe.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Overall&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I had a good time, and visiting Vegas for the first time was certainly an interesting experience. I&amp;#8217;m glad I went, and happy that we had a chance to participate. It was awesome to see (almost) everyone from the community in the flesh again, especially folks like Jeff and Ben, whom I&amp;#8217;ve been working on side projects with on and off. It&amp;#8217;s amazing how much easier it is to hash out ideas in person that it is over chat or phone conversations sometimes.&lt;/p&gt;
&lt;p&gt;Will I go again next year? I don&amp;#8217;t know. If it&amp;#8217;s in Vegas, probably not. As much as I enjoyed seeing the sites, frankly I felt that it was a bit distracting. If the conference &lt;strong&gt;is&lt;/strong&gt; in Vegas again next year, I certainly hope the organizers hold it somewhere other than the Hilton. Although it was easily accessible by monorail it&amp;#8217;s relatively removed from the rest of the strip, and the in-venue food and entertainment options there are limited to say the least. If I&amp;#8217;m going to be distracted, I at least want those distractions to be convenient! At least a drunk &lt;a href="http://en.wikipedia.org/wiki/Billy_Mays"&gt;Billy Mays&lt;/a&gt; was there (at the Hilton, attending another convention). Maybe next year we can get him to show us how to pitch our apps to consumers during a keynote? Maybe?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Vegas Next Week</title>
   <link href="http://blog.zerosum.org/2009/5/1/vegas-next-week.html" />
   <published>2009-05-01T00:00:00-04:00</published>
   <updated>2009-05-01T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/5/1/vegas-next-week</id>
   <content type="html">&lt;p&gt;So yeah, I&amp;#8217;m headed off to Vegas this weekend for &lt;a href="http://railsconf.com"&gt;Railsconf 2009&lt;/a&gt;. It&amp;#8217;ll be my first evar visit to that area of the country, and although it wouldn&amp;#8217;t have been my first choice for a conference location, I&amp;#8217;m really looking forward to it (also looking forward to a side trip to the grand canyon after the conference wraps).&lt;/p&gt;
&lt;p&gt;I hope to see some of you there and I know that everybody says this, but if you see me in the hallways, definitely come say hi and introduce yourself. To be honest, I often feel a bit overwhelmed at conferences and the things I remember most are the people that I meet and the discussions that we have in the hallways, during hack sessions, or over dinner and beers.&lt;/p&gt;
&lt;p&gt;While you&amp;#8217;re there don&amp;#8217;t forget to check out our &lt;a href="http://en.oreilly.com/rails2009/public/schedule/detail/7765"&gt;panel presentation for the Rails Rumble&lt;/a&gt; on Wednesday at 4:25. If you&amp;#8217;re going to be attending and want to record the presentation for us, please get in touch with me. You would be my personal hero. I&amp;#8217;m looking forward to a couple sessions in particular and I&amp;#8217;ll likely also be attending the &lt;a href="http://en.oreilly.com/rails2009/public/schedule/detail/8988"&gt;community organizers BoF&lt;/a&gt;, as a way to make up for the fact that I&amp;#8217;m missing out on the &lt;a href="http://neugsummit2009.pbworks.com"&gt;NE User Group Leader Summit&lt;/a&gt; tomorrow.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ll be staying at the Sahara during the conference and I&amp;#8217;ll probably be checking in occasionally on &lt;a href="http://brightkite.com/people/zapnap"&gt;BrightKite&lt;/a&gt; if you want to stalk me.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rdoc.info</title>
   <link href="http://blog.zerosum.org/2009/4/29/rdoc-info.html" />
   <published>2009-04-29T00:00:00-04:00</published>
   <updated>2009-04-29T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/4/29/rdoc-info</id>
   <content type="html">&lt;p&gt;For the past few months I&amp;#8217;ve been trying to roll out a 1 or 2-day micro-app every month. Because, why not &amp;#8212; it&amp;#8217;s fun and refreshing. In February there was &lt;a href="http://tweetdreams.org"&gt;tweetdreams&lt;/a&gt;, March was &lt;a href="http://github.com/zapnap/mogo"&gt;Mogo&lt;/a&gt; madness (in use at &lt;a href="http://offrails.org"&gt;offrails.org&lt;/a&gt;), and in April we spent a few days tossing &lt;a href="http://rdoc.info"&gt;this&lt;/a&gt; together.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.zerosum.org/assets/2009/4/22/cthulhu.png" alt="cthulhu approved" style="float:right; padding-left: 10px;"/&gt;&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;this&lt;/em&gt; that I refer to in the previous paragraph is &lt;a href="http://rdoc.info"&gt;Rdoc.info&lt;/a&gt;, a simple web service that generates documentation for Ruby libraries that are hosted on GitHub. You can &lt;a href="http://rdoc.info/projects/new"&gt;add a new project&lt;/a&gt; and it&amp;#8217;ll clone the repo from the hub of Git, use &lt;a href="http://github.com/lsegal/yard"&gt;&lt;span class="caps"&gt;YARD&lt;/span&gt;&lt;/a&gt; to generate rdocs, and then host them for you. So you can read them. Online. Because it loves you.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re the project owner, it&amp;#8217;s even better; just add the following simple post-commit hook to your project&amp;#8217;s settings in GitHub &lt;tt&gt;http://rdoc.info/projects/update&lt;/tt&gt; and it&amp;#8217;ll automatically regenerate documentation for you whenever you push to the remote. So yeah, unlike a random Twitter vanity application, it&amp;#8217;s like, actually useful and stuff.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve shown this to a few friends and they&amp;#8217;ve had some good suggestions for how to make it more useful. &lt;a href="http://neverlet.be/2009/4/27/full-text-searching-in-javascript"&gt;Jeff&lt;/a&gt;, in particular, had some really great ideas that we&amp;#8217;ve been looking into (more on that later, hopefully). Anyway, I&amp;#8217;ve doc&amp;#8217;d feature ideas in the project&amp;#8217;s &lt;a href="http://github.com/zapnap/rdocinfo/issues"&gt;GitHub Issues list&lt;/a&gt;, and although we plan to get to them sooner or later, I wanted to release it first as-is, in the spirit of &amp;#8220;release early, release often&amp;#8221;. If you want to help out, the project has been &lt;a href="http://github.com/zapnap/rdocinfo"&gt;open-sourced&lt;/a&gt; in the usual place.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rumble Panel Needs Your Help!</title>
   <link href="http://blog.zerosum.org/2009/4/22/rumble-panel-needs-your-help.html" />
   <published>2009-04-22T00:00:00-04:00</published>
   <updated>2009-04-22T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/4/22/rumble-panel-needs-your-help</id>
   <content type="html">&lt;p&gt;&lt;a href="http://railsconf.com"&gt;Railsconf&lt;/a&gt; is less than two weeks away. I&amp;#8217;m pretty excited because this year we&amp;#8217;re doing a Rails Rumble panel with a bunch of swell people who developed some pretty amazing things within the compressed event timeframe (48 hours). Winners and other innovators from both the 2007 and 2008 events will be present. The session is called &lt;a href="http://en.oreilly.com/rails2009/public/schedule/detail/7765"&gt;&amp;#8220;Starting Up Fast: Lessons from the Rails Rumble&amp;#8221;&lt;/a&gt; and the point of it is that these guys will be sharing the tips and tricks that let them build great stuff quick with Rails. Hopefully their advice will be applicable to your own startups and hobby projects, in &amp;#8220;real life&amp;#8221; as well as within the innovation competition atmosphere.&lt;/p&gt;
&lt;p&gt;So this is where we need your help. What do you want to ask them about? Project scoping for early and frequent iterations? Essential dev tools and techniques? Finding dependable partners / cofounders? General work habit questions? Inspirational mantras? Anything goes. Please submit your questions via &lt;a href="http://moderator.appspot.com/#16/e=53426"&gt;Google Moderator&lt;/a&gt;. The event will be recorded and made available afterwards, so you won&amp;#8217;t have to be in attendance to get your answers.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Why Namespaces Are Important</title>
   <link href="http://blog.zerosum.org/2009/4/17/why-namespaces-are-important.html" />
   <published>2009-04-17T00:00:00-04:00</published>
   <updated>2009-04-17T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/4/17/why-namespaces-are-important</id>
   <content type="html">&lt;p&gt;Apparently both &lt;a href='http://github.com/datamapper/extlib'&gt;Extlib&lt;/a&gt; and the &lt;a href='http://github.com/mbleigh/mash'&gt;Mash&lt;/a&gt; library, which the latest version of the &lt;a href='http://twitter.rubyforge.org'&gt;Twitter&lt;/a&gt; gem relies on, both define &lt;tt&gt;Mash&lt;/tt&gt; as a top-level class. This is lame.&lt;/p&gt;

&lt;p&gt;It means that if you&amp;#8217;re building an app that uses the Twitter gem to poll their API, you can&amp;#8217;t use DataMapper (which relies on Extlib) for your ORM. This is but one example of an affected application, of course (&lt;a href='http://gist.github.com/97193'&gt;retweet stack trace&lt;/a&gt;). Integrity&amp;#8217;s twitter notification support is another victim. &lt;a href='https://mbleigh.lighthouseapp.com/projects/10112/tickets/3-mash-conflicting-with-extlib'&gt;Epic namespacing fail&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So whose fault is this? The Mash library? Extlib? Which came first? Which is more widely used? OMFG fight!&lt;/p&gt;

&lt;p&gt;Seriously, who cares? If you&amp;#8217;re asking yourself these questions you&amp;#8217;re missing the point.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;module Org
  module Zerosum
    module Util
      class CollisionPrevention
        def initialize
          puts &amp;quot;gtfo&amp;quot;
        end
      end
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Java users, and consumers of other modern programming languages, figured out why namespacing was important a long time ago. In fact, one of the few things I actually liked from the Java world was it&amp;#8217;s use of hierarchal &lt;a href='http://en.wikipedia.org/wiki/Java_package'&gt;domain names in packages&lt;/a&gt; to ensure class name uniqueness and prevent this sort of ugly namespace collision. It&amp;#8217;s simple and effective. And yet we don&amp;#8217;t see a strategy like this in use in Ruby gems all that often. It&amp;#8217;s not like Ruby doesn&amp;#8217;t provide us with a mechanism for it; &lt;a href='http://www.rubycentral.com/pickaxe/tut_modules.html'&gt;Modules&lt;/a&gt; provide a really easy way to accomplish this. So why aren&amp;#8217;t we taking advantage of it in our libraries?&lt;/p&gt;

&lt;p&gt;I don&amp;#8217;t mean to single out Extlib and Mash in my rant here &amp;#8211; I&amp;#8217;m just picking on them because they happen to demonstrate an obvious problem that we&amp;#8217;ve all run into on occasion. Hell, I&amp;#8217;m guilty of it too. Anyway, the bottom line is, that if you intend your code to be sucked into someone else&amp;#8217;s application and reused, please do your best to prevent obvious namespace collisions. It&amp;#8217;s as easy as &lt;tt&gt;A::B::C&lt;/tt&gt; (or &lt;tt&gt;Tld::Domain::Feature::Specification&lt;/tt&gt;).&lt;/p&gt;

&lt;p&gt;Thanks for listening! :)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Getting Started with CouchDB</title>
   <link href="http://blog.zerosum.org/2009/4/6/getting-started-with-couchdb.html" />
   <published>2009-04-06T00:00:00-04:00</published>
   <updated>2009-04-06T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/4/6/getting-started-with-couchdb</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m a little late to the party on this one, but &lt;a href="http://couchdb.apache.org/"&gt;CouchDB&lt;/a&gt; sure is the new hotness. We&amp;#8217;ve been tossing around an idea for a new project and it&amp;#8217;s a great fit for so many reasons. Schema-less? Check. Distributed and fault-tolerant? Yup. Document revision-aware? &lt;em&gt;and&lt;/em&gt; it speaks &lt;span class="caps"&gt;JSON&lt;/span&gt; natively via a RESTful &lt;span class="caps"&gt;API&lt;/span&gt;? Oh yes. It&amp;#8217;s easy to see why so many people are getting excited about it.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re used to working with relational databases, it definitely requires a bit of mental reprogramming to really grok Couch, particularly when it comes to working with &lt;a href="http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views"&gt;views&lt;/a&gt; and designing &lt;a href="http://www.cmlenz.net/archives/2007/10/couchdb-joins"&gt;document relationships&lt;/a&gt; without traditional joins, etc etc. It&amp;#8217;s powerful stuff, and after working with it just a little bit, I&amp;#8217;m pretty enthusiastic, but still feel like I&amp;#8217;ve got a ton to learn.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.zerosum.org/assets/2009/4/6/logo.png" alt="CouchDB" style="float: right; margin: 10px 0 0 10px;" /&gt;&lt;/p&gt;
&lt;p&gt;Anyway, in terms of Ruby client interfaces&amp;#8230; there are a surprisingly large number of options that&amp;#8217;ll make your life easier. Candidates include &lt;a href="http://github.com/chuyeow/activecouch"&gt;ActiveCouch&lt;/a&gt;, &lt;a href="http://github.com/georgepalmer"&gt;CouchFu&lt;/a&gt;, and &lt;a href="http://github.com/paulcarey/relaxdb"&gt;RelaxDB&lt;/a&gt;. There&amp;#8217;s also a &lt;a href="http://github.com/datamapper/dm-more/tree/c428cee0d9865410d2aac94b76f866afa9c4e473/adapters/dm-couchdb-adapter"&gt;DataMapper adapter&lt;/a&gt;. My personal pick would have to be jchris&amp;#8217;s &lt;a href="http://github.com/jchris/couchrest"&gt;CouchRest&lt;/a&gt; library though. The core of it is very simple, modeled around Couch&amp;#8217;s own couch.js library. Plus, the ExtendedDocument model stuff gives you most of what you&amp;#8217;d want from a traditional &lt;span class="caps"&gt;ORM&lt;/span&gt; through properties, callbacks, validation mixins (lifted from DataMapper), in-line views (think of them as finder/scopes on steroids), attachments, and so on.&lt;/p&gt;
&lt;p&gt;Before diving in too deep I figured I&amp;#8217;d port a simple project over to Couch in order to familiarize myself with it. So I created a &lt;a href="http://github.com/zapnap/retweet/tree/couchdb"&gt;branch of the Retweet project&lt;/a&gt; that uses CouchRest instead of DataMapper. Check it out if you want to see how the CouchRest::ExtendedDocument stuff works in a simple project &amp;#8212; only one model in this case. It&amp;#8217;s quite nice. There&amp;#8217;s also a &lt;a href="http://github.com/zapnap/sinatra-template/tree/couchdb"&gt;CouchDB branch of sinatra-template&lt;/a&gt;, if you wanna use that to bootstrap your own ideas.&lt;/p&gt;
&lt;p&gt;Btw, if you&amp;#8217;re on a Mac, and using MacPorts, make sure to port selfupdate to the latest and greatest and then port install couchdb-devel to fetch CouchDB 0.9.0. Anything older than that won&amp;#8217;t work with CouchRest.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>New Biz Cards</title>
   <link href="http://blog.zerosum.org/2009/4/3/new-biz-cards.html" />
   <published>2009-04-03T00:00:00-04:00</published>
   <updated>2009-04-03T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/4/3/new-biz-cards</id>
   <content type="html">&lt;div&gt;
&lt;p&gt;&lt;img src="http://drop.io/download/public/gsnum3f63jtedx2sr8is/5608024d01ee93d662c7378df3065d0def9f45b6/97964df0-0236-012c-e1b2-f6016ced0891/c544acd0-0236-012c-1683-fa7fdd55425f/side1_large.jpg" width="210" height="360" style="float: left; padding-right: 10px;"/&gt;&lt;img src="http://drop.io/download/public/gsnum3f63jtedx2sr8is/fb00d30a1f406dcc0e961af9f61614c0dc028f64/97964df0-0236-012c-e1b2-f6016ced0891/ccefca80-0236-012c-5351-f599f1e1af13/side2_large.jpg" width="210" height="360" /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;So what do you think?&lt;/p&gt;
&lt;p&gt;Btw, it&amp;#8217;s true about the sci-fi gadgets &amp;#8212; they&amp;#8217;re made to order :). I&amp;#8217;m also available to build web applications, of course. Probably a better investment.&lt;/p&gt;
&lt;p&gt;And yes, the &lt;a href="http://nthmetal.com"&gt;Nth Metal&lt;/a&gt; (consulting business) site needs a bit of a makeover. All in due time.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Hello Mogo</title>
   <link href="http://blog.zerosum.org/2009/4/1/hello-mogo.html" />
   <published>2009-04-01T00:00:00-04:00</published>
   <updated>2009-04-01T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/4/1/hello-mogo</id>
   <content type="html">&lt;p&gt;&lt;em style="font-size: 1.15em; color: #666;"&gt;&amp;#8220;In brightest day, in blackest night, no feed shall escape my sight!&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;div style="float: right;"&gt;&lt;img src="http://blog.zerosum.org/assets/2009/4/1/mogo.jpg" alt="mogo" style="margin: 0 0 10px 10px;"/&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://github.com/zapnap/mogofeed"&gt;MogoFeed&lt;/a&gt; is a small planet-style feed aggregator built on top of &lt;a href="http://www.sinatrarb.com"&gt;Sinatra&lt;/a&gt;, leveraging &lt;a href="http://datamapper.org"&gt;DataMapper&lt;/a&gt; and Paul Dix&amp;#8217;s supa-fast &lt;a href="http://github.com/pauldix/feedzirra"&gt;Feedzirra&lt;/a&gt; library for the actual feed processing. It also teams up nicely with [the all-knowing, all-powerful] &lt;a href="http://sphinxsearch.com"&gt;Sphinx&lt;/a&gt;, making feed search a breeze. There&amp;#8217;s a working example of Mogo in action installed &lt;a href="http://offrails.org"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Source is &lt;a href="http://github.com/zapnap/mogofeed"&gt;available on GitHub&lt;/a&gt; so feel free to fork away if you&amp;#8217;re in need of such a thing. Patches and pull requests happily accepted.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Sinatra Isn't Pushy</title>
   <link href="http://blog.zerosum.org/2009/3/22/sinatra-presentation-nh-rb.html" />
   <published>2009-03-22T00:00:00-04:00</published>
   <updated>2009-03-22T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/3/22/sinatra-presentation-nh-rb</id>
   <content type="html">&lt;p&gt;I gave a hands-on introductory talk about &lt;a href="http://sinatrarb.com"&gt;Sinatra&lt;/a&gt; at last weeks &lt;a href="http://nhruby.org"&gt;NH.rb&lt;/a&gt; meetup. In case anyone is interested, I&amp;#8217;m also embedding the slides below. Looks like scribd butchered them a little bit, but you can always download the original set in &lt;span class="caps"&gt;PPT&lt;/span&gt; format or whatever too (follow the link).&lt;/p&gt;
&lt;p&gt;As you might expect, my presentation includes a number of borderline awful puns. Probably not as bad as the puns in a typical Git presentation, but still. You have been warned.&lt;/p&gt;
&lt;p&gt;&lt;a title="View A Quick Introduction to Sinatra (NH Ruby) on Scribd" href="http://www.scribd.com/doc/13462046/A-Quick-Introduction-to-Sinatra-NH-Ruby" style="margin: 12px auto 6px auto; font-family: Helvetica,Arial,Sans-serif; font-style: normal; font-variant: normal; font-weight: normal; font-size: 14px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none; display: block; text-decoration: underline;"&gt;A Quick Introduction to Sinatra (NH Ruby)&lt;/a&gt; &lt;object codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" id="doc_217527207806484" name="doc_217527207806484" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" align="middle"	height="500" width="100%" rel="media:presentation" resource="http://d.scribd.com/ScribdViewer.swf?document_id=13462046&amp;access_key=key-29a26upmxa2rzqqptbk1&amp;page=1&amp;version=1&amp;viewMode=" xmlns:media="http://search.yahoo.com/searchmonkey/media/" xmlns:dc="http://purl.org/dc/terms/" &gt;		&lt;param name="movie"	value="http://d.scribd.com/ScribdViewer.swf?document_id=13462046&amp;access_key=key-29a26upmxa2rzqqptbk1&amp;page=1&amp;version=1&amp;viewMode="&gt; 		&lt;param name="quality" value="high"&gt; 		&lt;param name="play" value="true"&gt;		&lt;param name="loop" value="true"&gt; 		&lt;param name="scale" value="showall"&gt;		&lt;param name="wmode" value="opaque"&gt; 		&lt;param name="devicefont" value="false"&gt;		&lt;param name="bgcolor" value="#ffffff"&gt; 		&lt;param name="menu" value="true"&gt;		&lt;param name="allowFullScreen" value="true"&gt; 		&lt;param name="allowScriptAccess" value="always"&gt; 		&lt;param name="salign" value=""&gt;    				&lt;embed src="http://d.scribd.com/ScribdViewer.swf?document_id=13462046&amp;access_key=key-29a26upmxa2rzqqptbk1&amp;page=1&amp;version=1&amp;viewMode=" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" play="true" loop="true" scale="showall" wmode="opaque" devicefont="false" bgcolor="#ffffff" name="doc_217527207806484_object" menu="true" allowfullscreen="true" allowscriptaccess="always" salign="" type="application/x-shockwave-flash" align="middle"  height="500" width="100%"&gt;&lt;/embed&gt;					 							&lt;span rel="media:thumbnail" href="http://i.scribd.com/public/images/uploaded/13232486/ea3K3acaQ2Z4h0rXZjd_thumbnail.jpeg"&gt; 						&lt;span property="media:title"&gt;A Quick Introduction to Sinatra (NH Ruby)&lt;/span&gt;			&lt;span property="dc:creator"&gt;zapnap&lt;/span&gt; 						&lt;span property="dc:type" content="Text"&gt; 			&lt;/object&gt;&lt;/p&gt;
&lt;p&gt;A &lt;a href="http://nhruby.org/2009/3/20/sinatra-css-fundamentals-recap"&gt;full meetup report&lt;/a&gt; is available as well. You can find the &lt;a href="http://github.com/nhruby/pickawinner"&gt;full source&lt;/a&gt; for the sample door prize chooser app that we live-coded during the presentation via GitHub.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Design Refresh</title>
   <link href="http://blog.zerosum.org/2009/3/21/design-refresh.html" />
   <published>2009-03-21T00:00:00-04:00</published>
   <updated>2009-03-21T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2009/3/21/design-refresh</id>
   <content type="html">&lt;p&gt;It was about time, I guess. This blog had been in need of a facelift for many many moons. Anyway, let me know what you think. It&amp;#8217;s rocking a tweaked-out version of the classic cutline theme that &lt;a href="http://github.com/zapnap/mephisto-cutline-theme"&gt;I ported to Mephisto/Liquid&lt;/a&gt; with some supernatural green custom goodness. The banner image is a photo of some awesome graffiti I found in a bathroom in a Burlington VT bar last October. I know how that guy feels.&lt;/p&gt;
&lt;p&gt;I also pooped out a tiny personal microsite earlier this week, which you can find over at &lt;a href="http://nickplante.info"&gt;nickplante.info&lt;/a&gt; if you&amp;#8217;d like to stalk me further. Eye-burning green highlights ftw.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rumble Panel At Railsconf</title>
   <link href="http://blog.zerosum.org/2009/3/1/rumble-panel-at-railsconf.html" />
   <published>2009-03-01T00:00:00-05:00</published>
   <updated>2009-03-01T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2009/3/1/rumble-panel-at-railsconf</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m happy to report that our panel, &lt;a href="http://en.oreilly.com/rails2009/public/schedule/detail/7765"&gt;Starting Up Fast: Lessons from the Rails Rumble&lt;/a&gt;, has been accepted for the 4th annual &lt;a href="http://en.oreilly.com/rails2009/"&gt;Railsconf&lt;/a&gt; event in Las Vegas.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.railsconf.com/"&gt;&lt;br /&gt;
&lt;img src="http://assets.en.oreilly.com/1/event/24/rails2009_banner_speaking_125x125.jpg" width="125" height="125"  border="0"  alt="RailsConf 2009" title="RailsConf 2009" style="float:left; padding-right: 10px;" /&gt;&lt;br /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll be moderating a panel of competition winners and participants, and we&amp;#8217;ll be discussing how they were able to achieve some impressive feats in the compressed contest timeframe. It should be packed full of useful real-world advice on how to organize and launch Rails applications quickly. We&amp;#8217;ll also talk about the event itself, and the nature of innovation competitions in general (and why you should get involved!) I guarantee that it will be fun, but I can make no guarantee about whether or not there will be choreographed mock-fighting. That&amp;#8217;s up to you.&lt;/p&gt;
&lt;p&gt;Panelists include our friends &lt;a href="http://faithfulgeek.org"&gt;Joe Fiorini&lt;/a&gt; (grand prize winner 2008), &lt;a href="http://gethandcrafted.com"&gt;Josh Owens&lt;/a&gt; (grand prizer winner 2007, design award 2008), &lt;a href="http://www.culann.com/"&gt;Ben Scofield&lt;/a&gt; (winner, solo division for both 2007 and 2008), &lt;a href="http://giraffesoft.ca"&gt;James Golick&lt;/a&gt; (winner, most useful 2008), and &lt;a href="http://blog.ninjahideout.com/"&gt;Darcy Laycock&lt;/a&gt;, who participated in the 2007 contest and joined the organizational team for the 2008 event.&lt;/p&gt;
&lt;p&gt;So if you&amp;#8217;re making the voyage to the City of Sin in May, make sure to check us out. I&amp;#8217;m excited, and it&amp;#8217;ll be great to meet many of you there! Also, you can teach me how to gamble. I hear that I have a pretty bad tell. Whatever that is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;UPDATE&lt;/span&gt; 3/16:&lt;/strong&gt; The panel is scheduled for May 6th from 4:25pm to 5:15pm &lt;span class="caps"&gt;PDT&lt;/span&gt; in Pavilion 9 &amp;#8211; 10&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Micro App: Tweet Dreams</title>
   <link href="http://blog.zerosum.org/2009/2/4/microapp-tweetdreams.html" />
   <published>2009-02-04T00:00:00-05:00</published>
   <updated>2009-02-04T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2009/2/4/microapp-tweetdreams</id>
   <content type="html">&lt;p&gt;I was feeling kind of &lt;i&gt;meh&lt;/i&gt; last week, so I decided I&amp;#8217;d take a day off from the paid projects and hack out an &amp;#8216;app-in-a-day&amp;#8217; microapp. If you know me, you know that this is something I talk about doing all the time and publicly advocate, but rarely find the time to actually execute on ;-). I&amp;#8217;d really like to change that, and devote more time to my own projects this year.&lt;/p&gt;
&lt;p&gt;Of course, the hardest part about doing this sort of thing is coming up with a concept that can be created and deployed within the timeframe you have available. For the &lt;a href="http://railsrumble.com"&gt;Rumble&lt;/a&gt;, we gave teams of 4 people 2 full days, and lots of prep time. But in this case I wanted to see what I could do with a designer in, say, an afternoon, without any advance planning at all. Just for fun. So I chatted up my designer friend &lt;a href="http://tyrauber.com"&gt;Ty&lt;/a&gt; and we came up with the concept of a really simple &lt;a href="http://twitter.com"&gt;Twitter&lt;/a&gt;-based dream journal, that would display random tweets that had to do with what people were dreaming about. Nothing fancy, sort of a rip off of &lt;a href="http://ohmyscience.org"&gt;OhMyScience&lt;/a&gt; but without the science. Because who needs science, right?&lt;/p&gt;
&lt;p&gt;Ty whipped up a fun single page &lt;a href="http://en.wikipedia.org/wiki/Goodnight_Moon"&gt;Goodnight-Moon-inspired&lt;/a&gt; design and I wrote a tiny amount of code to morph my &lt;a href="http://github.com/zapnap/sinatra-template"&gt;Sinatra app template&lt;/a&gt; into a Twitter keyword aggregator, and about 3 hours later &lt;a href="http://tweetdreams.org"&gt;tweetdreams.org&lt;/a&gt; was ready to go. It may not be the most innovative or featureful website you&amp;#8217;ve seen this week, but it&amp;#8217;s cute and was fun to build and a few people have said some nice things about it. Frankly, that&amp;#8217;s enough for me.&lt;/p&gt;
&lt;p&gt;&lt;img src="/assets/2009/2/3/tweetdreams.jpg" alt="Tweet Dreams"/&gt;&lt;/p&gt;
&lt;p&gt;The moral of the story is that you don&amp;#8217;t have to do something earth-shattering, massive, or insanely innovative to enjoy doing it. If you&amp;#8217;re feeling kind of down or like your current work projects are &lt;a href="http://www.youtube.com/watch?v=0jMl1z0SmLg"&gt;neverenders&lt;/a&gt;, block out a day and bang out a microapp. Just shipping something will often make you feel better about yourself, regardless of the complexity involved. Don&amp;#8217;t be afraid to call it &amp;#8216;v1.0&amp;#8217; and move on to the next one. On the web, nothing is every finished. And that&amp;#8217;s a good thing.&lt;/p&gt;
&lt;p&gt;So yeah, &lt;a href="http://tweetdreams.org"&gt;check it out&lt;/a&gt; if you&amp;#8217;re interested. &lt;a href="http://github.com/zapnap/retweet"&gt;The sub-100 lines of source&lt;/a&gt;, sans Ty&amp;#8217;s awesome theme, is also up on teh GitHubs if you wanna make your own Twitter-fueled microapp.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>The Way You Wear Your Hat</title>
   <link href="http://blog.zerosum.org/2009/1/23/the-way-you-wear-your-hat.html" />
   <published>2009-01-23T00:00:00-05:00</published>
   <updated>2009-01-23T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2009/1/23/the-way-you-wear-your-hat</id>
   <content type="html">&lt;p&gt;So the &lt;a href="http://sinatra.github.com"&gt;Sinatra&lt;/a&gt; guys just kicked out v0.9. Classy and well-dressed, as always. If you haven&amp;#8217;t played around with Sinatra before, you should really give it a look. It&amp;#8217;s often everything I need for building lightweight micro-apps. Very &lt;a href="http://sinatra.rubyforge.org/book.html"&gt;easy to learn&lt;/a&gt; and use, too.&lt;/p&gt;
&lt;p&gt;Of course, Sinatra is intentionally quite small and doesn&amp;#8217;t dictate what testing framework, &lt;span class="caps"&gt;ORM&lt;/span&gt;, or templating language you use. Having choices is great, but using a common set of tools with Sinatra can also cut down on initial configuration time and make it even more appealing for quick tasks.&lt;/p&gt;
&lt;p&gt;Personally I&amp;#8217;ve found that my own ideal application template consists of &lt;a href="http://rspec.info"&gt;RSpec&lt;/a&gt;, &lt;a href="http://haml.hamptoncatlin.com"&gt;Haml&lt;/a&gt;, &lt;a href="http://datamapper.rubyforge.org"&gt;DataMapper&lt;/a&gt;, and a few bits of well-placed glue. If you want to give Sinatra a spin, and just want some sensible defaults baked-in from the get-go, check out the &lt;a href="http://github.com/zapnap/sinatra-template"&gt;application template&lt;/a&gt; that I pushed to GitHub earlier today. It should help get you up and running fast. And it might make pancakes for you too (but probably not).&lt;/p&gt;
&lt;p&gt;Just &lt;a href="http://github.com/zapnap/sinatra-template"&gt;fork the repository&lt;/a&gt;, rename it, and start writing specs and code. When you&amp;#8217;re done, use the included Rackup script to deploy it via Passenger. Couldn&amp;#8217;t be easier. If you have any criticisms, suggestions, or improvements, let me know. Or hey, just send a pull request.&lt;/p&gt;
&lt;p&gt;Thanks to Ryan Tomayko, Blake Mizerany, and the rest of the Sinatra team for creating such a fun (and truly minimalist) web framework.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>New Radiant Extensions</title>
   <link href="http://blog.zerosum.org/2009/1/13/new-radiant-extensions.html" />
   <published>2009-01-13T00:00:00-05:00</published>
   <updated>2009-01-13T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2009/1/13/new-radiant-extensions</id>
   <content type="html">&lt;p&gt;We launched a new &lt;a href="http://radiantcms.org"&gt;Radiant&lt;/a&gt;-based site for a client last month. It was a small project but involved the creation of a couple new extensions, so I thought I&amp;#8217;d take the opportunity to &lt;span class="caps"&gt;OSS&lt;/span&gt; them. In case anyone is interested&amp;#8230;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://github.com/zapnap/radiant-flash-gallery-extension"&gt;Flash Gallery Extension&lt;/a&gt; &amp;#8212; An extension that works with Todd Domineyâ€™s excellent &lt;a href="http://slideshowpro.net/"&gt;SlideShowPro&lt;/a&gt; (&lt;span class="caps"&gt;SSP&lt;/span&gt;) Flash component to easily create elegant Flash-based media galleries within Radiant (Note that &lt;span class="caps"&gt;SSP&lt;/span&gt; is a commercial product; however a trial version is available suitable for testing this extension).&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://github.com/zapnap/radiant-upcoming-events-extension"&gt;Upcoming Events Extension&lt;/a&gt; &amp;#8212; An uber-simple extension that allows creation and management of important dates within a Radiant &lt;span class="caps"&gt;CMS&lt;/span&gt; instance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is all.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>NHRuby &amp; the Importance of User Groups</title>
   <link href="http://blog.zerosum.org/2008/12/27/nhruby-the-importance-of-user-groups.html" />
   <published>2008-12-27T00:00:00-05:00</published>
   <updated>2008-12-27T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/12/27/nhruby-the-importance-of-user-groups</id>
   <content type="html">&lt;p&gt;There are some changes in store for &lt;a href="http://nhruby.org"&gt;NHRuby&lt;/a&gt; in 2009. Group founder &lt;a href="http://blog.zenlinux.com/?p=240"&gt;Scott Garman&lt;/a&gt; is headed out to the west coast and is therefore stepping down as coordinator, and I&amp;#8217;ll be stepping in to fill the void. Over the past 2 years Scott has done a great job getting things started and lining up interesting content. I hope we can keep the momentum going in his absence!&lt;/p&gt;
&lt;p&gt;Meetings will continue to be held at &lt;span class="caps"&gt;RMC&lt;/span&gt; Research in Portsmouth (&lt;a href="http://nhruby.org/about"&gt;directions&lt;/a&gt;), but the dates will shift slightly; from this point forward we&amp;#8217;ll be meeting on the &lt;strong&gt;third Thursday&lt;/strong&gt; of the month. We&amp;#8217;ve also set up &lt;a href="http://groups.google.com/group/nhruby-discuss"&gt;new mailing lists&lt;/a&gt; and a &lt;a href="http://nhruby.org"&gt;new website&lt;/a&gt; to document group activities and associated shenanigans. I&amp;#8217;ll be migrating more archival material over from the wiki shortly.&lt;/p&gt;
&lt;p&gt;The 2009 event calendar kicks off to a great start with a talk by &lt;a href="http://www.vaporbase.com"&gt;Jon Linowes&lt;/a&gt; on January 15th. He&amp;#8217;ll be speaking about &lt;a href="http://www.reviewramp.com"&gt;ReviewRamp&lt;/a&gt;, his Rails-based startup, &lt;a href="http://github.com/aslakhellesoy/cucumber/tree/master"&gt;Cucumber&lt;/a&gt; integration testing, and his own DynamicRecord framework. If you&amp;#8217;re in the southern Maine, New Hampshire, or northern Massachusetts area I really encourage you to come out and hang with us. We&amp;#8217;re a small, friendly group, and new people of all skill levels are always welcome.&lt;/p&gt;
&lt;p&gt;Never been to your local user group? You&amp;#8217;re really missing out. Attending them is a great way to learn firsthand about new ideas and technologies from passionate people who actually give a shit. It&amp;#8217;s also a great way to network and &lt;a href="http://www.mojombo.com/2008/11/03/how-to-meet-your-next-cofounder.html"&gt;find other folks to bounce ideas off of or work on projects with you&lt;/a&gt;. The Internet is a great place to meet people too, of course, but there&amp;#8217;s just something special about meeting someone in person, being able to pop your hand up in the middle of a talk to get clarification, or grabbing a beer or two after an inspiring discussion. Also, it&amp;#8217;s easier to tell if they&amp;#8217;re trying to manipulate you into sending them money. If you haven&amp;#8217;t yet attended your local user group(s), make it part of your new years resolution to change that.&lt;/p&gt;
&lt;p&gt;And if your area doesn&amp;#8217;t have a user group? Then start one. You might be surprised at who shows up.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Merb 2 == Rails 3</title>
   <link href="http://blog.zerosum.org/2008/12/23/merb-2-rails-3.html" />
   <published>2008-12-23T00:00:00-05:00</published>
   <updated>2008-12-23T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/12/23/merb-2-rails-3</id>
   <content type="html">&lt;p&gt;Wow. Well, &lt;a href="http://weblog.rubyonrails.org/2008/12/23/merb-gets-merged-into-rails-3"&gt;this&lt;/a&gt; is&amp;#8230; somewhat &lt;a href="http://brainspl.at/articles/2008/12/23/merb-is-rails"&gt;unexpected&lt;/a&gt;. And &lt;a href="http://yehudakatz.com/2008/12/23/rails-and-merb-merge/"&gt;very&lt;/a&gt;, &lt;a href="http://ryandaigle.com/articles/2008/12/23/what-s-new-in-edge-rails-merb"&gt;very&lt;/a&gt; &lt;a href="http://merbist.com/2008/12/23/rails-and-merb-merge/"&gt;cool&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="/assets/2008/12/23/merbrails.jpg"/&gt;&lt;/p&gt;
&lt;p&gt;No kidding, right? Personally, I&amp;#8217;m excited. I think the Merb 2 / Rails 3 announcement makes a ton of sense (read the links above for details); Rails with a modular Merb-like architecture and a set of reasonable Rails-ish defaults is an epic win for both camps, if done right. It&amp;#8217;s truly an exciting time to be a Ruby developer. Happy holidays everyone.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Why I Love Vim</title>
   <link href="http://blog.zerosum.org/2008/12/7/why-i-love-vim.html" />
   <published>2008-12-07T00:00:00-05:00</published>
   <updated>2008-12-07T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/12/7/why-i-love-vim</id>
   <content type="html">&lt;p&gt;Back when I was a Java developer, I knew and really liked me some &lt;a href="http://www.jetbrains.com/"&gt;IntelliJ&lt;/a&gt;. Later, when I moved over to Ruby full time, &lt;a href="http://www.netbeans.org/"&gt;NetBeans&lt;/a&gt; seemed like a damn good choice. After all, I was used to having a &amp;#8220;proper&amp;#8221; &lt;span class="caps"&gt;IDE&lt;/span&gt;, it had pretty nice Ruby support and also, much to my joy, it had a &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=3653"&gt;Vim plugin&lt;/a&gt;, which allowed me to use my favorite editor from my pre-IntelliJ days. Win.&lt;/p&gt;
&lt;p&gt;Fast forward to about six months ago when I decided that I&amp;#8217;d ceased to care about heavyweight IDEs. I just didn&amp;#8217;t use enough of their features to make their overall (often cumbersome) weight and memory footprint worthwhile. So goodbye NetBeans with Vim plugin and hello Vim. &lt;a href="http://code.google.com/p/macvim/"&gt;MacVim&lt;/a&gt;, specifically.&lt;/p&gt;
&lt;p&gt;Why Vim? Because Vim is universal. Because Vim is love.&lt;/p&gt;
&lt;p&gt;Dave Thomas and Andy Hunt famously wrote &lt;i&gt;&amp;#8220;Choose an editor, know it thoroughly, and use it for all editing tasks&amp;#8221;&lt;/i&gt; in their seminal masterpiece, &lt;a href="http://www.pragprog.com/the-pragmatic-programmer"&gt;The Pragmatic Programmer&lt;/a&gt;. I couldn&amp;#8217;t agree more. There is no tool in a programmer&amp;#8217;s toolbox more important than an editor, and the importance of knowing it inside and out cannot be understated. For me, ever since college, that editor has always been Vim. It was just everywhere that I needed it to be. It was ubiquitous. I could use Vim at home on my desktop, at school, at work in the campus &lt;span class="caps"&gt;NOC&lt;/span&gt;, at the CS lab, and in any number of remote shell sessions, on even the most obscure platforms. One ring to rule them all.&lt;/p&gt;
&lt;p&gt;Vim is also small, and quick. Once you know what you&amp;#8217;re doing, it&amp;#8217;s quicker and easier to manipulate text in Vim than any other editor that I&amp;#8217;m aware of. Of course, the learning curve is steep, relative to other editors. But it&amp;#8217;s worth it. When I&amp;#8217;m writing code, switching between files, replacing text, et al, I don&amp;#8217;t want to have to use the mouse too frequently. Vim, in all of it&amp;#8217;s keyboard-centric glory, delivers. MacVim also provides awesome mouse highlighting and menu option support, for the best of both worlds.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s also massive value in Vim&amp;#8217;s powerful plugins system. Without some of these awesome third party extensions folks have developed for Vim, it wouldn&amp;#8217;t be nearly as appealing as a desktop code editor. But by adding plugins like &lt;a href="http://www.vim.org/scripts/script.php?script_id=1658"&gt;NERDTree&lt;/a&gt;, &lt;a href="http://www.vim.org/scripts/script.php?script_id=1567"&gt;rails.vim&lt;/a&gt;, &lt;a href="http://www.vim.org/scripts/script.php?script_id=90"&gt;vcscommand.vim&lt;/a&gt;, and &lt;a href="http://www.vim.org/scripts/script.php?script_id=1984"&gt;FuzzyFinder&lt;/a&gt;, it becomes a full-fledged programmers editor for me, something that easily outguns TextMate, NetBeans, Komodo, and all the other would-be competitors. Customize it to your hearts content.&lt;/p&gt;
&lt;p&gt;Anyway, I just wanted to put that out there. Vim rules. And &lt;a href="http://tpope.net"&gt;Tim Pope&lt;/a&gt;, author of rails.vim, rules too (even though he looks awful in drag). His plugin, along with NERDTree, vastly simplifies my day to day editing tasks, and reproduces all the functionality I would have actually used from a more fully-featured &lt;span class="caps"&gt;IDE&lt;/span&gt;. Thanks guys. You&amp;#8217;re my heroes.&lt;/p&gt;
&lt;p&gt;For more information on using Vim as a Ruby developer, see &lt;a href="http://weblog.jamisbuck.org/2008/10/10/coming-home-to-vim"&gt;Jamis Buck&amp;#8217;s&lt;/a&gt; post from a few months back about switching back to Vim from TextMate. It&amp;#8217;s a well-written argument, but the really amazing thing about the article is the number of comments it generated. It&amp;#8217;s great to see so much love for such a great editor and I&amp;#8217;m glad to be in such good company.&lt;/p&gt;
&lt;p&gt;So, what&amp;#8217;s your favorite go-to editor? If it&amp;#8217;s Vim, I&amp;#8217;d be curious to know what plugins you&amp;#8217;re using and how you&amp;#8217;ve customized it.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;PS If you&amp;#8217;re also a MacVim user, make sure you install the &lt;a href="http://vim.wikia.com/wiki/Deleting_a_buffer_without_closing_the_window"&gt;:Bclose&lt;/a&gt; script too!&lt;/i&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Demystifying Rails Plugin Development</title>
   <link href="http://blog.zerosum.org/2008/11/18/demystifying-rails-plugin-development.html" />
   <published>2008-11-18T00:00:00-05:00</published>
   <updated>2008-11-18T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/11/18/demystifying-rails-plugin-development</id>
   <content type="html">&lt;p&gt;My slides from the &lt;a href="http://voicesthatmatter.com/ruby2008/"&gt;Voices that Matter&lt;/a&gt; (Pro Ruby 2008) conference&amp;#8230;&lt;/p&gt;
&lt;p&gt;&lt;a title="View Demystifying Rails Plugin Development document on Scribd" href="http://www.scribd.com/doc/7976548/Demystifying-Rails-Plugin-Development" style="margin: 12px auto 6px auto; font-family: Helvetica,Arial,Sans-serif; font-style: normal; font-variant: normal; font-weight: normal; font-size: 14px; line-height: normal; font-size-adjust: none; font-stretch: normal; -x-system-font: none; display: block; text-decoration: underline;"&gt;Demystifying Rails Plugin Development&lt;/a&gt; &lt;object codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" id="doc_880515275864122" name="doc_880515275864122" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" align="middle"	height="500" width="100%"&gt;		&lt;param name="movie"	value="http://documents.scribd.com/ScribdViewer.swf?document_id=7976548&amp;access_key=key-23j7t5bsahdroct0xrdb&amp;page=1&amp;version=1&amp;viewMode="&gt; 		&lt;param name="quality" value="high"&gt; 		&lt;param name="play" value="true"&gt;		&lt;param name="loop" value="true"&gt; 		&lt;param name="scale" value="showall"&gt;		&lt;param name="wmode" value="opaque"&gt; 		&lt;param name="devicefont" value="false"&gt;		&lt;param name="bgcolor" value="#ffffff"&gt; 		&lt;param name="menu" value="true"&gt;		&lt;param name="allowFullScreen" value="true"&gt; 		&lt;param name="allowScriptAccess" value="always"&gt; 		&lt;param name="salign" value=""&gt;    		&lt;embed src="http://documents.scribd.com/ScribdViewer.swf?document_id=7976548&amp;access_key=key-23j7t5bsahdroct0xrdb&amp;page=1&amp;version=1&amp;viewMode=" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" play="true" loop="true" scale="showall" wmode="opaque" devicefont="false" bgcolor="#ffffff" name="doc_880515275864122_object" menu="true" allowfullscreen="true" allowscriptaccess="always" salign="" type="application/x-shockwave-flash" align="middle"  height="500" width="100%"&gt;&lt;/embed&gt;	&lt;/object&gt;&lt;/p&gt;
&lt;p&gt;Thanks to everyone who attended and of course to the organizers for putting together a great conference.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Vote Or Die</title>
   <link href="http://blog.zerosum.org/2008/10/26/vote-or-die.html" />
   <published>2008-10-26T00:00:00-04:00</published>
   <updated>2008-10-26T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/10/26/vote-or-die</id>
   <content type="html">&lt;p&gt;OK, I&amp;#8217;m being a bit overly dramatic. But seriously, go &lt;a href="http://railsrumble.com/login"&gt;sign up&lt;/a&gt; to judge and vote in the &lt;a href="http://railsrumble.com"&gt;2008 Rails Rumble&lt;/a&gt;. Help us decide which of the amazing web applications featured on our &lt;a href="http://railsrumble.com/entries"&gt;leaderboard&lt;/a&gt; deserves to take home the goods. Oh, and tell your friends. The more opinions the better.&lt;/p&gt;
&lt;p&gt;If you need extra motivation, we&amp;#8217;re giving away a number of Amazon gift certificates to random voters. There&amp;#8217;s still time, but hurry up; voting ends November 1st.&lt;/p&gt;
&lt;p&gt;While we&amp;#8217;re on the subject, there&amp;#8217;s also another &lt;a href="http://en.wikipedia.org/wiki/U.S._presidential_election,_2008"&gt;important election&lt;/a&gt; coming up too ;-). I&amp;#8217;m not going to pretend to tell you who to vote for, but (if you&amp;#8217;re a US citizen) just make sure you understand the issues at stake and vote responsibly. Thanks!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>OpenID, Simplified</title>
   <link href="http://blog.zerosum.org/2008/10/11/open-id-simplified.html" />
   <published>2008-10-11T00:00:00-04:00</published>
   <updated>2008-10-11T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/10/11/open-id-simplified</id>
   <content type="html">&lt;p&gt;The build portion of the &lt;a href="http://railsrumble.com"&gt;Rails Rumble&lt;/a&gt; is next weekend. Wow, time really flies, eh? It seems like it&amp;#8217;s only been a few weeks since we announced it. We filled all 200 seats this year and even had to open up a few more. I&amp;#8217;m really amped, and am looking forward to seeing some truly amazing microapps come out of this weekend sprint. I think they&amp;#8217;re going to be even better than last years&amp;#8217;. I hope you&amp;#8217;ll help prove me right.&lt;/p&gt;
&lt;p&gt;Anyway, I posted earlier today over on the &lt;a href="http://blog.railsrumble.com/2008/10/11/support-openid-just-do-it"&gt;Rumble blog&lt;/a&gt; about our decision to mandate &lt;a href="http://openid.net"&gt;OpenID&lt;/a&gt; usage in the registration (and voting) app and &lt;a href="http://janrain.com"&gt;JanRain&lt;/a&gt;&amp;#8216;s involvement in the Rumble as a sponsor. We&amp;#8217;re using their new &lt;a href="http://www.janrain.com/products/opx"&gt;&lt;span class="caps"&gt;OPX&lt;/span&gt; &lt;span class="caps"&gt;ASP&lt;/span&gt; service&lt;/a&gt; to provide branded railsrumble.com OpenIDs to users who don&amp;#8217;t have them. It&amp;#8217;s pretty great. We really didn&amp;#8217;t want to run our own provider and then be saddled with the upkeep of it. It makes much more sense to delegate that to a third party who is an expert in that realm.&lt;/p&gt;
&lt;p&gt;Personally I think OpenID is, for the most part, pretty swank. Yes, it has its flaws. And maybe it isn&amp;#8217;t a proper fit for &lt;strong&gt;every&lt;/strong&gt; application. But for an event of this sort, a decentralized identity / login system is absolutely critical. It would be silly to force users to create dozens of different accounts (all with different login names, password criteria, etc) just to evaluate new applications.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m both excited and relieved that providing OpenID registration services is becoming easier and easier. It&amp;#8217;s really about time and SaaS OpenID facilities makes a ton of sense for sites, like us, that want the benefits of providing OpenID without the hassle of operating and maintaining it long-term.&lt;/p&gt;
&lt;p&gt;I expect a lot of competitors this year to use Jim Neath&amp;#8217;s &lt;a href="http://github.com/fudgestudios/bort/tree/rumble_safe"&gt;Bort&lt;/a&gt; or a similar blank slate Rails application to bootstrap their development. This is a good thing and it doesn&amp;#8217;t void the rules in any shape or form as long as the kit is just bundling plugins and not providing major application functionality in and of itself (like Radiant or Spree does). One of the best things about Bort is that it supports OpenID right out of the box, in addition to stock Restful Authentication style user accounts. Epic win for you. And your users.&lt;/p&gt;
&lt;p&gt;If you aren&amp;#8217;t using Bort or something similar, you may want to check out our &lt;a href="http://github.com/zapnap/open_id_simplified"&gt;OpenID Simplified plugin&lt;/a&gt;, which was extracted from the Rumble voting app itself. It&amp;#8217;s a combination of the classic OpenID Authentication plugin with some bits from Restful Auth, and a few extras to make adding OpenID-based user accounts to your application dead simple. What it doesn&amp;#8217;t do, however, is provide non-OpenID-enabled account creation.&lt;/p&gt;
&lt;p&gt;&amp;#8220;Wait, what? You can&amp;#8217;t create accounts with it?,&amp;#8221; you ask, &amp;#8220;What were you thinking?&amp;#8221;&lt;/p&gt;
&lt;p&gt;First of all, yes, you&amp;#8217;re right. OpenID isn&amp;#8217;t ubiquitous yet. And maybe it never will be. But it&amp;#8217;s certainly better (at least imo) than creating yet another user account with yet another set of credentials (or worse yet, the same set). Options like the free &lt;a href="https://www.myopenid.com/affiliate"&gt;MyOpenID affiliate program&lt;/a&gt; and JanRain&amp;#8217;s branded &lt;span class="caps"&gt;OPX&lt;/span&gt; service make it just as easy to have users proxy-register with them as it is to create a one-off local user account. By signing up with one of these services you can provide your own logo and copy and have the logged-in user directed back to your site, once they complete the signup process.&lt;/p&gt;
&lt;p&gt;Also, by integrating the &lt;a href="http://idselector.com"&gt;ID Selector&lt;/a&gt; widget, many of your users even realize that they actually already have an OpenID account &amp;#8211; via Flickr, Blogger, Wordpress, etc &amp;#8211; and therefore bypass this unnecessary registration situation altogether.&lt;/p&gt;
&lt;p&gt;My point is that, although it may not yet be perfect, we&amp;#8217;re getting to the point with OpenID services where adding support for them is almost as straightforward as implementing our own local accounts system. Many of your users will already have an OpenID account. Sometimes they just need to be made aware of it. For those who don&amp;#8217;t, it&amp;#8217;s becoming easier and easier to allow them to create an account that they can use anywhere, without placing the burden for maintenance of that on yourself.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Testing Workling with RSpec</title>
   <link href="http://blog.zerosum.org/2008/10/4/testing-workling-with-rspec.html" />
   <published>2008-10-04T00:00:00-04:00</published>
   <updated>2008-10-04T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/10/4/testing-workling-with-rspec</id>
   <content type="html">&lt;p&gt;&lt;a href="http://github.com/purzelrakete/workling"&gt;Workling&lt;/a&gt; is my current sauce of choice for interfacing with message queues and performing asynchronous background tasks in Rails apps. We&amp;#8217;re using it in production in a couple of places (with &lt;a href="http://github.com/starling/starling"&gt;Starling&lt;/a&gt;) and it works great. In fact, we liked it so much that we wrote about it in &lt;a href="http://railsplugins.com"&gt;Practical Rails Plugins&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Anyway, one thing we didn&amp;#8217;t discuss there was how to test your workers. I&amp;#8217;m an &lt;a href="http://rspec.info"&gt;RSpec&lt;/a&gt; junkie, and I want to make sure that my Workers are behaving the way that I expect at all times. The solution is pretty simple. I modified a code snippet written a while back by &lt;a href="http://gensym.org/2007/5/30/using-rspec-with-backgroundrb-workers"&gt;David Altenburg&lt;/a&gt; to spec his BackgroundRB workers&amp;#8230;&lt;/p&gt;
&lt;p&gt;Just add the following to your &lt;code&gt;spec/spec_helper.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module Workling
  class Base
    class RailsBase
      def self.register; end
    end
  end
end&lt;/code&gt;

&lt;code&gt;worker_path = File.dirname(__FILE__) + "/../app/workers"
spec_files = Dir.entries(worker_path).select {|x| /\.rb\z/ =~ x}
spec_files -= [ File.basename(__FILE__) ]
spec_files.each { |path| require(File.join(worker_path, path)) }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can add specs for your workers to &lt;code&gt;spec/workers/my_worker_spec.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;require File.dirname(__FILE__) + '/../spec_helper'&lt;/code&gt;

&lt;code&gt;describe MyWorker do
  it "should manufacture a new widget at the happy castle widget foundry" do
    Widget.should_receive(:find).with(1).and_return(@widget = mock_model(Widget))
    @widget.should_receive(:manufacture)
    MyWorker.asynch_manufacture_widget(:widget_id =&amp;gt; 1)
  end
end
&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Register for the Rails Rumble!</title>
   <link href="http://blog.zerosum.org/2008/9/29/register-for-the-rails-rumble.html" />
   <published>2008-09-29T00:00:00-04:00</published>
   <updated>2008-09-29T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/9/29/register-for-the-rails-rumble</id>
   <content type="html">&lt;p&gt;Registration for the 2008 Rails Rumble opened last Friday. If you haven&amp;#8217;t already registered and want to compete, &lt;a href="http://railsrumble.com"&gt;you better hurry up&lt;/a&gt;. There are only 25 seats remaining (out of a maximum of 200!) at the time of this writing. I&amp;#8217;m guessing those will be gone very, very soon.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://blog.railsrumble.com/assets/2008/9/24/RailsRumbleBadge_180_1.png" style="float:right; padding: 0 10px 10px 10px" /&gt;&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ve been working hard to make this years competition even better than last year and I think everyone is going to have a lot of fun. In addition to all the great prizes that sponsors are putting on the table, and the insane amount of community goodwill surrounding the event, there are also a number of companies running &lt;a href="http://blog.railsrumble.com/workshare"&gt;workshare programs&lt;/a&gt;. If you&amp;#8217;re a fan of the &lt;a href="http://coworking.pbwiki.com/"&gt;coworking&lt;/a&gt; concept you may want to check these out. I know I&amp;#8217;m wishing there was one in my town.&lt;/p&gt;
&lt;p&gt;On the other hand, if you&amp;#8217;re geographically isolated from the rest of the Ruby world, don&amp;#8217;t despair! It&amp;#8217;s a virtual competition and you can compete from anywhere. Look at it as a great opportunity to assemble a distributed team of entrepreneurially-minded developers and designers and see how well you can work with each other. If you&amp;#8217;re looking for people or ideas, make sure to check out the #railsrumble channel on the Freenode &lt;span class="caps"&gt;IRC&lt;/span&gt; network or post to &lt;a href="http://blog.railsrumble.com"&gt;the blog&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Upcoming Speaking Gigs</title>
   <link href="http://blog.zerosum.org/2008/9/15/upcoming-speaking-gigs.html" />
   <published>2008-09-15T00:00:00-04:00</published>
   <updated>2008-09-15T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/9/15/upcoming-speaking-gigs</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve firmed up a few speaking gigs for the next couple months. And I wanted to share.&lt;/p&gt;
&lt;p&gt;First of all, tomorrow night, September 16th, I&amp;#8217;ll be presenting a &amp;#8220;casual intro&amp;#8221; to every-day &lt;a href="http://git.or.cz"&gt;Git&lt;/a&gt; usage at &lt;a href="http://wiki.nhruby.org"&gt;NH.rb&lt;/a&gt;. Brian Turnbull and Scott Garman will also be presenting, on &lt;span class="caps"&gt;HTTP&lt;/span&gt; and Rails deployment stacks, respectively.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.voicesthatmatter.com/ruby2008/"&gt;&lt;img src="http://blog.zerosum.org/assets/2008/9/15/Ruby125x125.jpg" style="float:right; padding: 10px 0 10px 10px;"/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you live in the ME/NH/Northern MA area and are interested in Ruby, I really encourage you to come to these meetings. They&amp;#8217;re a great way to meet other local developers and learn about new cutting edge topics. If you can&amp;#8217;t make this one, the next one is scheduled for October 21st (they&amp;#8217;re always on the third Tuesday of the month). I&amp;#8217;m scheduled to speak at that one, too. Topic is currently &lt;span class="caps"&gt;TBD&lt;/span&gt; but I&amp;#8217;m sure we&amp;#8217;ll come up with something fun.&lt;/p&gt;
&lt;p&gt;Meeting other Rubyists and learning about hot new tech isn&amp;#8217;t enough of a reward in and of itself? Well, there&amp;#8217;s free swag too. This month we&amp;#8217;ll be giving away a few copies of my new book, Practical Rails Plugins along with some other Apress goodies (thanks Apress!).&lt;/p&gt;
&lt;p&gt;NH.rb is also giving way a free core conference pass to the upcoming &lt;a href="http://www.voicesthatmatter.com/ruby2008/"&gt;Voices That Matter: Professional Ruby Conference&lt;/a&gt; (Boston, November 17-20). Pretty great, right? Sounds like this is going to be a great conference and they have a bunch of top notch speakers lined up. I&amp;#8217;ll be there too (how was that for a segue?), speaking about Rails Plugin development strategies on the first day of the event. Hope to see you there!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>jQueryConf 2008 Agenda</title>
   <link href="http://blog.zerosum.org/2008/9/1/jqueryconf-2008-agenda.html" />
   <published>2008-09-01T00:00:00-04:00</published>
   <updated>2008-09-01T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/9/1/jqueryconf-2008-agenda</id>
   <content type="html">&lt;p&gt;The JQuery  team just announced the &lt;a href="http://jquery.com/blog/2008/08/31/jquery-conference-2008-agenda/"&gt;agenda for JQueryConf 2008&lt;/a&gt; and it looks pretty solid! I&amp;#8217;m happy that I registered early, as it appears to have sold out.&lt;/p&gt;
&lt;p&gt;Last year&amp;#8217;s &amp;#8220;camp&amp;#8221; was great and I&amp;#8217;m sure this year will be even better, with two tracks to cater to both beginning and advanced developers. The only item from my wish list that&amp;#8217;s missing from the agenda is unit testing JQuery client code (and plugins). Oh well! If you&amp;#8217;re interested in this topic, &lt;a href="http://www.lostechies.com/blogs/chad_myers/archive/2008/08/28/getting-started-with-jquery-qunit-for-client-side-javascript-testing.aspx"&gt;Chad Meyers&lt;/a&gt; just wrote up a great intro to using JQuery&amp;#8217;s very own &lt;a href="http://docs.jquery.com/QUnit"&gt;QUnit&lt;/a&gt; testrunner over on his blog. Good stuff!&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Update 9/29&lt;/b&gt;: I posted a summary of conference highlights over at &lt;a href="http://dobbscodetalk.com/index.php?option=com_myblog&amp;show=jQueryConf-2008-Highlights.html&amp;Itemid=29"&gt;&lt;span class="caps"&gt;DDJ&lt;/span&gt; Code Talk&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>2008 Rails Rumble Kickoff</title>
   <link href="http://blog.zerosum.org/2008/8/26/2008-rails-rumble-kickoff.html" />
   <published>2008-08-26T00:00:00-04:00</published>
   <updated>2008-08-26T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/8/26/2008-rails-rumble-kickoff</id>
   <content type="html">&lt;p&gt;We just set up the new blog site for the &lt;a href="http://blog.railsrumble.com"&gt;2008 Rails Rumble&lt;/a&gt; contest. This year the event will be held the weekend of October 18th. Registration should open within the next couple weeks. That is to say, we&amp;#8217;re working on it. Read the &lt;a href="http://blog.railsrumble.com/overview"&gt;faq&lt;/a&gt; &amp;#8217;n &lt;a href="http://blog.railsrumble.com/rules"&gt;rules&lt;/a&gt; for more info.&lt;/p&gt;
&lt;p&gt;Greets to co-organizers &lt;a href="http://blog.ninjahideout.com/"&gt;Darcy&lt;/a&gt;, &lt;a href="http://shinelogic.com/"&gt;Erin&lt;/a&gt;, &lt;a href="http://carterparks.com"&gt;Carter&lt;/a&gt;, &lt;a href="http://brianturnbull.com"&gt;Brian&lt;/a&gt;, and &lt;a href="http://blog.divoxx.com/"&gt;Rodrigo&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Practical Rails Plugins</title>
   <link href="http://blog.zerosum.org/2008/8/23/practical-rails-plugins.html" />
   <published>2008-08-23T00:00:00-04:00</published>
   <updated>2008-08-23T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/8/23/practical-rails-plugins</id>
   <content type="html">&lt;p&gt;Hey wow, author copies of my book just showed up yesterday. That&amp;#8217;s pretty cool. My side of things has been finished for a few months now, but it&amp;#8217;s nice to finally see it in print!&lt;/p&gt;
&lt;p&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=httprailsplco-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=1590599934&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;m=amazon&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" style="width:120px;height:240px;float:right;padding: 0 0 5px 10px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;The book, &lt;a href="http://railsplugins.com"&gt;Practical Rails Plugins&lt;/a&gt; (Apress 2008), is aimed at the beginning to intermediate Rails developer, featuring a number of recipes for using popular third party plugins in Rails projects. So it&amp;#8217;s sort of a recipes book but with a focus on leveraging plugins to accelerate feature development, and on standalone mini-projects rather than code snippets, which I think is much more illustrative for developers who are new to the framework. Topics include video transcoding and asynchronous processing, state machine modeling, payment processing, geocoding, full text search, testing and a whole lot more.&lt;/p&gt;
&lt;p&gt;I wrote about 50% of the content, &lt;a href="http://berubeconsulting.com"&gt;David Berube&lt;/a&gt; (author of Practical Ruby Gems and Practical Reporting with Ruby and Rails) is responsible for the rest. If you want to pick up a copy, you can order it via &lt;a href="http://www.amazon.com/dp/1590599934?tag=httprailsplco-20&amp;camp=14573&amp;creative=327641&amp;linkCode=as1&amp;creativeASIN=1590599934&amp;adid=0GFN5VB50QR0V5XBS4CA&amp;"&gt;Amazon&lt;/a&gt;. We also put up a &lt;a href="http://railsplugins.com"&gt;companion site&lt;/a&gt; for the book last week, if you wanna check it out.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Razume in the News</title>
   <link href="http://blog.zerosum.org/2008/8/6/razume-in-the-news.html" />
   <published>2008-08-06T00:00:00-04:00</published>
   <updated>2008-08-06T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/8/6/razume-in-the-news</id>
   <content type="html">&lt;p&gt;Just wanted to take a quick moment to call attention to &lt;a href="http://www.techcrunch.com/2008/08/05/launchbox-unleashes-its-first-nine-startups/"&gt;this TechCrunch article&lt;/a&gt; which announces the unveiling of LaunchBox Digital&amp;#8217;s first nine startups.&lt;/p&gt;
&lt;p&gt;My favorite of the group is &lt;a href="http://razume.com"&gt;Razume&lt;/a&gt;, a collaborative resume review service. But hey, I&amp;#8217;m a little biased &amp;mdash; we know those guys! For the past couple months, we&amp;#8217;ve had the pleasure of helping them develop their Rails-based online resume building tools, document management, and peer review features. It&amp;#8217;s been a fun ride and it&amp;#8217;s great to see them finally launched and seeing some much deserved attention.&lt;/p&gt;
&lt;p&gt;In any case, congratulations to Sam, Brian, and the rest of the team on the formal launch. Razume is sure to be an indispensable resource for recent college grads, connecting them with professional resume experts and like minded job seekers. Rock on, Wayne.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Debugging ActionScript in the Browser</title>
   <link href="http://blog.zerosum.org/2008/7/31/debugging-actionscript-in-the-browser.html" />
   <published>2008-07-31T00:00:00-04:00</published>
   <updated>2008-07-31T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/7/31/debugging-actionscript-in-the-browser</id>
   <content type="html">&lt;p&gt;Alright, so the dirty truth of it is that I used to do a fair bit of Flash / ActionScript work. No, I&amp;#8217;m not ashamed. Flash can be a real pain in the ass but I really do enjoy using it for tasks like interactive widgets and media playback. And it&amp;#8217;s a fantastic tool for information visualization (I wrote a &lt;a href="http://r-s-g.org/carnivore/download.php"&gt;Carnivore client library for AS 2.0&lt;/a&gt; way back in the day). I&amp;#8217;ve been more focused on Ruby work these days, but from time to time I still dabble and do the occasional bit of Flash work for a &lt;a href="http://kosaminore.com"&gt;badass creative agency&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In any case, if you&amp;#8217;re developing applications or widgets for browser-based deployment with Flash, you&amp;#8217;ve doubtlessly noticed that certain things just don&amp;#8217;t work the same way in the &amp;#8216;Test Movie&amp;#8217; facility as they do in the browser (cough cough &lt;code&gt;MovieClipLoader&lt;/code&gt; cough). Fortunately, there&amp;#8217;s a way to see your &lt;code&gt;trace()&lt;/code&gt; logger messages in a live browser session, too.&lt;/p&gt;
&lt;p&gt;First, you need to download and install a &lt;a href="http://www.adobe.com/support/flashplayer/downloads.html"&gt;debug version&lt;/a&gt; of the Flash Player in Firefox. Next, install Alessandro Crugnola&amp;#8217;s &lt;a href="http://www.sephiroth.it/firefox/flashtracer"&gt;Flash Tracer&lt;/a&gt; plugin. An older version for FF2 is available at the Firefox addons site, so make sure to snag the one from the link in this article if you&amp;#8217;re using Firefox 3.&lt;/p&gt;
&lt;p&gt;After restarting the browser, you can select &amp;#8216;Flash Tracer&amp;#8217; from the Tools menu and it&amp;#8217;ll pop up a sidebar that will contain any logger ouput in currently loaded SWFs. Make sure to adjust your preferences to specify the log file location and max lines of history to maintain. It&amp;#8217;s really an invaluable tool for when Test Movie just ain&amp;#8217;t cuttin it. Thanks Alessandro!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>NH Merb</title>
   <link href="http://blog.zerosum.org/2008/7/13/nh-merb.html" />
   <published>2008-07-13T00:00:00-04:00</published>
   <updated>2008-07-13T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/7/13/nh-merb</id>
   <content type="html">&lt;p&gt;This Tuesday (July 15th), NH Ruby morphs into NH Merb for the night! Guest speaker &lt;a href="http://jeremydurham.com"&gt;Jeremy Durham&lt;/a&gt; is coming up from Boston to give a talk about his journey converting an existing Rails app to &lt;a href="http://merbivore.com"&gt;Merb&lt;/a&gt;. Should be good stuff, especially for those of you who are curious about Merb and how it might be of benefit to you as a Rails alternative.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re in the seacoast area, make sure to stop by. As always, more details and directions on the &lt;a href="http://wiki.nhruby.org"&gt;wiki&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Passenger &lt;3 Sinatra</title>
   <link href="http://blog.zerosum.org/2008/7/4/passenger-3-sinatra.html" />
   <published>2008-07-04T00:00:00-04:00</published>
   <updated>2008-07-04T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/7/4/passenger-3-sinatra</id>
   <content type="html">&lt;p&gt;A couple people have asked me how I&amp;#8217;m hosting the &lt;a href="http://sinatrarb.com"&gt;Sinatra&lt;/a&gt;-based &lt;a href="http://paste.zerosum.org"&gt;pastie service&lt;/a&gt; we wrote in yesterday&amp;#8217;s revised &lt;a href="http://blog.zerosum.org/2008/7/2/clone-pastie-with-sinatra-datamapper-redux"&gt;tutorial&lt;/a&gt;. The previous version ran on a mongrel handler frontended by nginx, but for this version I decided to try something a little different.&lt;/p&gt;
&lt;p&gt;One of the big announcements at Railsconf last month was that &lt;a href="http://modrails.com"&gt;Passenger&lt;/a&gt; (aka mod_rails) would be releasing a v2.0 with support not only for Rails applications but also for &lt;a href="http://rack.rubyforge.org"&gt;Rack&lt;/a&gt;, meaning that any Rack-based Ruby web framework can also run on it. Yay for deployment options, right? So anyway, I figured we&amp;#8217;d give that a shot.&lt;/p&gt;
&lt;p&gt;For those of you who haven&amp;#8217;t yet mucked with it, Passenger is dead simple to setup. Run &lt;code&gt;gem install passenger&lt;/code&gt; to pull down the gem, and execute the &lt;code&gt;passenger-install-apache2-module&lt;/code&gt; command to build and install the Apache 2.2 module (you&amp;#8217;ll need the proper Apache libraries to be present of course). The command output will show you how to configure Apache to load the module.&lt;/p&gt;
&lt;p&gt;Getting Passenger to run a Sinatra-based application also turned out to be remarkably easy. All you need to do is create a regular old Rackup script. The file will need to be named &lt;code&gt;config.ru&lt;/code&gt; and should contain all the logic necessary to initialize our app:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;require 'rubygems'
require 'sinatra'&lt;/code&gt;

&lt;code&gt;Sinatra::Application.default_options.merge!(
  :run =&amp;gt; false,
  :env =&amp;gt; ENV['RACK_ENV']
)&lt;/code&gt;

&lt;code&gt;require 'toopaste'
run Sinatra.application&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Place this file in the folder on your server where &lt;code&gt;toopaste.rb&lt;/code&gt; and the &lt;code&gt;views&lt;/code&gt; directory reside.&lt;/p&gt;
&lt;p&gt;Next, create a &lt;code&gt;public&lt;/code&gt; directory. This is where any static images, JavaScripts, or stylesheets would be kept (we&amp;#8217;re not using any, in this simple example). Point your vhost&amp;#8217;s &lt;code&gt;DocumentRoot&lt;/code&gt; here:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
  ServerName paste.zerosum.org
  DocumentRoot /var/www/apps/toopaste/public
  ...
&amp;lt;/VirtualHost&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might as well create a &lt;code&gt;tmp&lt;/code&gt; directory too. You can place a &lt;code&gt;restart.txt&lt;/code&gt; file in this directory to tell Passenger it needs to reload the app without restarting Apache (you can &lt;a href="http://blog.zerosum.org/2008/5/5/random-passenger-observations"&gt;use this in your cap restart tasks, too&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Couldn&amp;#8217;t be much easier. For more information on deploying other Rack-based frameworks (&lt;a href="http://wiki.merbivore.com/pages/phusion-passenger"&gt;Merb&lt;/a&gt;, Camping, Ramaze, etc) and various other config options, check Passenger&amp;#8217;s &lt;a href="http://www.modrails.com/documentation/Users%20guide.html#_deploying_a_rack_based_ruby_application"&gt;user guide&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Clone Pastie with Sinatra &amp; DataMapper 0.9</title>
   <link href="http://blog.zerosum.org/2008/7/2/clone-pastie-with-sinatra-datamapper-redux.html" />
   <published>2008-07-02T00:00:00-04:00</published>
   <updated>2008-07-02T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/7/2/clone-pastie-with-sinatra-datamapper-redux</id>
   <content type="html">&lt;p&gt;Waaaay back in November I wrote a &lt;a href="http://blog.zerosum.org/2007/11/5/build-a-simple-pastie-clone-with-sinatra-datamapper-in-15-minutes"&gt;DataMapper and Sinatra tutorial&lt;/a&gt;. DM was still pretty immature at the time, and it quickly became outdated. I promised I&amp;#8217;d update it once 0.9 was released.&lt;/p&gt;
&lt;p&gt;Better late than never, right? Anyway, without further ado, here&amp;#8217;s Toopaste Tutorial 2.0:&lt;/p&gt;
&lt;h4&gt;What We&amp;#8217;re Building&lt;/h4&gt;
&lt;p&gt;Today we&amp;#8217;re going to learn how to write a dirt simple pastie clone using Sinatra and Datamapper. For those of you unfamiliar with pastie systems, they&amp;#8217;re commonly used in &lt;span class="caps"&gt;IRC&lt;/span&gt; to paste bits of code to a globally-visible place outside of the channel. So you copy some code from your &lt;span class="caps"&gt;IDE&lt;/span&gt;, paste it into a web page, submit it, and the Pastie system fancies it up with some syntax highlighting or whatnot. You can then copy the resultant &lt;span class="caps"&gt;URL&lt;/span&gt; and paste it back into the channel so other people can view it.&lt;/p&gt;
&lt;p&gt;Examples of this type of service include &lt;a href="http://pastie.caboo.se"&gt;pastie.caboo.se&lt;/a&gt; and &lt;a href="http://www.rafb.net/paste/"&gt;Nopaste&lt;/a&gt; @ rafb.net. Those sites do a lot of extra cool stuff, like allow you to select the language for different syntax highlighting rules, select themes for viewing, and so on. But the core concept itself isn&amp;#8217;t a terribly complex one, and our example is going to be about as barebones as they come.&lt;/p&gt;
&lt;p&gt;The interesting thing isn&amp;#8217;t the application we&amp;#8217;re going to build here so much as it is the tools we&amp;#8217;ll use. That is, we&amp;#8217;ll be using the pastie example to introduce you to two cool new pieces of Ruby tech: Sinatra, a Ruby web micro-framework, and the DataMapper &lt;span class="caps"&gt;ORM&lt;/span&gt; package.&lt;/p&gt;
&lt;h4&gt;Sinatra&lt;/h4&gt;
&lt;p&gt;&lt;a href="http://sinatrarb.com"&gt;Sinatra&lt;/a&gt;, on the surface, is a lot like &lt;a href="http://redhanded.hobix.com/bits/campingAMicroframework.html"&gt;Camping&lt;/a&gt;, another Ruby web all-in-one-file micro-framework. Camping hasn&amp;#8217;t seen much active development lately though, and the syntax can be a bit strange for new users. Sinatra is much more straight-forward and accessible. It&amp;#8217;s really a kind of domain-specific language for writing simple web applications, used to define RESTful actions and how they should be handled. This makes it perfect for lightweight mini-apps. It&amp;#8217;s also &lt;span class="caps"&gt;ORM&lt;/span&gt;-agnostic, instead of being married to ActiveRecord like both Rails and Camping are.&lt;/p&gt;
&lt;p&gt;Sinatra has been making cameo appearances supporting a number of high-profile Ruby-based web apps, including Heroku and GitHub. It runs on top of &lt;a href="http://rack.rubyforge.org"&gt;Rack&lt;/a&gt;, which means that it plays nice with a wide variety of Ruby web app servers, including Mongrel, Thin, and Ebb. It also means that you can host your Sinatra applications easily with Apache and Phusion &lt;a href="http://modrails.com"&gt;Passenger&lt;/a&gt;, as of Passenger 2.0. For more information, &lt;a href="http://www.xnot.org/sinatra/beginning.html"&gt;check out the &amp;#8216;official&amp;#8217; Sinatra tutorial&lt;/a&gt; (oops dead link). There&amp;#8217;s also an &lt;a href="http://github.com/cschneid/sinatra-book"&gt;open source Sinatra book&lt;/a&gt; in the works.&lt;/p&gt;
&lt;h4&gt;DataMapper&lt;/h4&gt;
&lt;p&gt;&lt;a href="http://datamapper.org"&gt;DataMapper&lt;/a&gt; is the new &lt;span class="caps"&gt;ORM&lt;/span&gt; package on the block, and an alternative to ActiveRecord (and Og and Sequel and so on). It just moved into town but it&amp;#8217;s already sitting at the cool kid lunch table. Whereas AR implements the ActiveRecord Pattern, DataMapper (surprise!) implements the DataMapper pattern.&lt;/p&gt;
&lt;p&gt;There are a number of reasons why I prefer this approach, but that&amp;#8217;s fodder for an entirely separate blog post, so I won&amp;#8217;t get into it here. Besides, the team has already written a &lt;a href="http://datamapper.org/why.html"&gt;great summary of why DataMapper rocks&lt;/a&gt;. Read it. It&amp;#8217;s good stuff. Oh, and performance kicks ass too.&lt;/p&gt;
&lt;p&gt;Take that, non-believers!&lt;/p&gt;
&lt;h4&gt;Prerequisites&lt;/h4&gt;
&lt;p&gt;OK, anyway. Tutorial time. Found your plastic hat? Good. Let&amp;#8217;s go. First let&amp;#8217;s get the gems we&amp;#8217;ll need. As of this writing, DM is at v0.9.2 and Sinatra is at v0.2.2. We&amp;#8217;re also going to retrieve the &lt;a href="http://syntaxi.rubyforge.org"&gt;Syntaxi&lt;/a&gt; gem, which we&amp;#8217;ll use for syntax highlighting.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo gem install sinatra data_mapper syntaxi&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;data_mapper&lt;/code&gt; gem is a &amp;#8220;meta gem&amp;#8221; that includes the most commonly used gems from &lt;code&gt;dm-core&lt;/code&gt;, &lt;code&gt;dm-more&lt;/code&gt;, and others. We&amp;#8217;ll be using a couple of these additional libraries &amp;#8212; &lt;code&gt;dm-timestamps&lt;/code&gt; and &lt;code&gt;dm-validations&lt;/code&gt; &amp;#8212; in this tutorial.&lt;/p&gt;
&lt;p&gt;Since DM uses the &lt;a href="http://rubyforge.org/projects/dorb"&gt;DataObjects.rb&lt;/a&gt; (DO) drivers, you&amp;#8217;ll want to install them too. For this tutorial we&amp;#8217;ll be using Sqlite3 as a data store. If you want to use MySQL or Postgres or any other database supported by DO, well that&amp;#8217;s cool too (just make sure to get &lt;code&gt;do\_mysql&lt;/code&gt; or &lt;code&gt;do\_postgres&lt;/code&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo gem install data_objects do_sqlite3&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;The Code&lt;/h4&gt;
&lt;p&gt;Now that our prerequisites are satisfied, let&amp;#8217;s get started by creating the file &lt;code&gt;toopaste.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;require 'sinatra'
require 'dm-core'
require 'dm-validations'
require 'dm-timestamps'
require 'syntaxi'&lt;/code&gt;

&lt;code&gt;DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/toopaste.sqlite3")&lt;/code&gt;

&lt;code&gt;class Snippet
  include DataMapper::Resource&lt;/code&gt;

&lt;code&gt;  property :id,         Integer, :serial =&amp;gt; true    # primary serial key
  property :body,       Text,    :nullable =&amp;gt; false # cannot be null
  property :created_at, DateTime
  property :updated_at, DateTime&lt;/code&gt;

&lt;code&gt;  # validates_present :body
  # validates_length :body, :minimum =&amp;gt; 1&lt;/code&gt;

&lt;code&gt;  Syntaxi.line_number_method = 'floating'
  Syntaxi.wrap_at_column = 80&lt;/code&gt;

&lt;code&gt;  def formatted_body
    replacer = Time.now.strftime('[code-%d]')
    html = Syntaxi.new("[code lang='ruby']#{self.body.gsub('[/code]', replacer)}[/code]").process
    "&amp;lt;div class=\"syntax syntax_ruby\"&amp;gt;#{html.gsub(replacer, '[/code]')}&amp;lt;/div&amp;gt;"
  end
end&lt;/code&gt;

&lt;code&gt;DataMapper.auto_upgrade!&lt;/code&gt;

&lt;code&gt;# new
get '/' do
  erb :new
end&lt;/code&gt;

&lt;code&gt;# create
post '/' do
  @snippet = Snippet.new(:body =&amp;gt; params[:snippet_body])
  if @snippet.save
    redirect "/#{@snippet.id}"
  else
    redirect '/'
  end
end&lt;/code&gt;

&lt;code&gt;# show
get '/:id' do
  @snippet = Snippet.get(params[:id])
  if @snippet
    erb :show
  else
    redirect '/'
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next we&amp;#8217;ll dissect this code listing to give you a brief look at how DataMapper and Sinatra work. We&amp;#8217;ll show the code listings for our views as we get to them.&lt;/p&gt;
&lt;h4&gt;Code Analysis: DataMapper&lt;/h4&gt;
&lt;p&gt;The first couple lines require the libraries we&amp;#8217;ll be using in this example. &lt;code&gt;dm-core&lt;/code&gt; represents the DataMapper core libraries, and &lt;code&gt;dm-validations&lt;/code&gt; and &lt;code&gt;dm-timestamps&lt;/code&gt; both add extra bits of non-core functionality to DataMapper. In this case, requiring timestamps means that fields such as &lt;code&gt;created\_at&lt;/code&gt; and &lt;code&gt;updated\_at&lt;/code&gt; automatically get branded with the current Date/Time when a model is created or updated. As for validations, well we&amp;#8217;ll see them in use shortly.&lt;/p&gt;
&lt;p&gt;Before we create out first DataMapper-backed model we have to set up the database. The following line sets the default database connection and tells it to use the Sqlite3 file-based database in the current working directory. It won&amp;#8217;t exist yet but don&amp;#8217;t worry, we&amp;#8217;ll be creating it automatically when we migrate.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/toopaste.sqlite3")&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;Persistent Models and Properties&lt;/h5&gt;
&lt;p&gt;Next we define our model, &lt;code&gt;Snippet&lt;/code&gt;. Since we want to persist snippets, we include the &lt;code&gt;DataMapper::Resource&lt;/code&gt; module in the class definition. From an end user point of view this is the same as inheriting from &lt;code&gt;ActiveRecord::Base&lt;/code&gt; in Active Record. It&amp;#8217;s a nice bonus that we don&amp;#8217;t have to use inheritance to accomplish this any more.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;include DataMapper::Resource&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The property declarations in our model are DataMapper&amp;#8217;s way of specifying attributes, which translate to database table columns. This might look a little bit odd at first if you&amp;#8217;re coming over from Active Record&amp;#8230;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;#8220;&lt;span class="caps"&gt;OMG&lt;/span&gt; I don&amp;#8217;t have to put comments in my source file to remind me what attributes are available on my models?!&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s like a little slice of heaven, isn&amp;#8217;t it?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;property :id,         Integer, :serial =&amp;gt; true    # primary serial key
property :body,       Text,    :nullable =&amp;gt; false # cannot be null
property :created_at, DateTime
property :updated_at, DateTime&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The only two required parameters are the name of the property and the type, but you can also add other options to mark a property as the primary serial key, prevent it from being null, and so on. Properties get public accessors by default, but you can modify that by setting the &lt;code&gt;:accessor&lt;/code&gt; option to &lt;code&gt;:private&lt;/code&gt; or &lt;code&gt;:protected&lt;/code&gt; (&lt;code&gt;:reader&lt;/code&gt; and &lt;code&gt;:writer&lt;/code&gt; options are also supported for even more control).&lt;/p&gt;
&lt;p&gt;Another interesting DM optimization worth noting: by default, the text field (&lt;code&gt;body&lt;/code&gt;) is lazily loaded. Text columns are expensive in databases, and by using lazy loading, we only access them when they&amp;#8217;re needed. This speeds things up significantly in most cases. However, if you don&amp;#8217;t want to do this for whatever reason, you can just pass a &lt;code&gt;:lazy =&amp;gt; false&lt;/code&gt; option in the text column property declaration.&lt;/p&gt;
&lt;h5&gt;Validation&lt;/h5&gt;
&lt;p&gt;The validators we&amp;#8217;re specifying should look relatively familiar to anyone familiar with AR. They&amp;#8217;re only available to us because we required the &lt;code&gt;dm-validations&lt;/code&gt; library, as mentioned. This is part of DM&amp;#8217;s Merb-like minimalist approach; start with just the bare essentials, and allow developers to mix in extra functionality as its desired. The kitchen sink is so fail, right?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# validates_present :body
# validates_length :body, :minimum =&amp;gt; 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So why are these lines commented out then, you ask?&lt;/p&gt;
&lt;p&gt;Well, we could explicitly add the &lt;code&gt;validates_present :body&lt;/code&gt; to specify that the body property must be present, but that&amp;#8217;s already handled for us in the property declaration since we specified &lt;code&gt;:nullable =&amp;gt; false&lt;/code&gt;. If &lt;code&gt;dm-validations&lt;/code&gt; is not required, the nullable option will simply ensure that the database column isn&amp;#8217;t null, but if validations are in use it will augment this behavior to assume that we not only mean &amp;#8216;not null&amp;#8217;, but also &amp;#8216;not empty&amp;#8217;.&lt;/p&gt;
&lt;p&gt;Likewise, &lt;code&gt;validates_length&lt;/code&gt; could be useful in certain situations, but in our case we just want to make sure that the paste body isn&amp;#8217;t empty, which is already handled for us by the nullable option on the body property.&lt;/p&gt;
&lt;p&gt;There are lots of other validations that we can add in this manner, of course. For more information see the &lt;a href="http://datamapper.rubyforge.org/"&gt;DataMapper &lt;span class="caps"&gt;API&lt;/span&gt; documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h5&gt;Syntax Highlighting with Syntaxi&lt;/h5&gt;
&lt;p&gt;The only custom method we&amp;#8217;ve added to our model, &lt;code&gt;formatted_body&lt;/code&gt;, is pretty straightforward. It just takes the body of our snippet (a property on the model) and wraps it in some code that gives us pretty syntax highlighting and line numbering. Syntaxi leverages Jamis Buck&amp;#8217;s &lt;a href="http://syntax.rubyforge.org/"&gt;Syntax gem&lt;/a&gt; to mark up the specified code, wrapping &lt;span class="caps"&gt;CSS&lt;/span&gt; span tags around things that should be colored, adding line numbers, and some other goodies too &amp;#8212; you&amp;#8217;ll see the &lt;span class="caps"&gt;CSS&lt;/span&gt; in our layout shortly.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def formatted_body
  replacer = Time.now.strftime('[code-%d]')
  html = Syntaxi.new("[code lang='ruby']#{self.body.gsub('[/code]', replacer)}[/code]").process
  "&amp;lt;div class=\"syntax syntax_ruby\"&amp;gt;#{html.gsub(replacer, '[/code]')}&amp;lt;/div&amp;gt;"
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;replacer&lt;/code&gt; stuff just keeps us from stumbling on syntax coloring markup in our output &lt;span class="caps"&gt;HTML&lt;/span&gt;.&lt;/p&gt;
&lt;h5&gt;Auto-Migrations&lt;/h5&gt;
&lt;p&gt;Now that we&amp;#8217;re done defining our database-backed model, we&amp;#8217;re just about ready to move on to the web-serving portion of the tutorial. But first, we need to tell DataMapper to create the appropriate database table if it doesn&amp;#8217;t already exist. We do this by using the &lt;code&gt;DataMapper.auto\_upgrade!&lt;/code&gt; method, which checks to see if the database table that corresponds to our model(s) need upgrading and then creates or updates them as appropriate. It&amp;#8217;s a non-destructive way to do auto-migrations (the destructive equivalent is &lt;code&gt;auto\_migrate!&lt;/code&gt;)&lt;/p&gt;
&lt;h4&gt;Code Analysis: Sinatra&lt;/h4&gt;
&lt;p&gt;Moving on to the Sinatra portion of our tutorial, you&amp;#8217;ll see that routes and actions are intimately married in Sinatra. Although this may not be desirable for a larger application, it&amp;#8217;s great for smaller, simpler web apps like this pastie project. In this case we&amp;#8217;re talking uber-simple; we only have three actions and they&amp;#8217;re only ever available at these three &lt;span class="caps"&gt;URL&lt;/span&gt; patterns.&lt;/p&gt;
&lt;h5&gt;The Index Action / New Snippet Form&lt;/h5&gt;
&lt;p&gt;The first of our actions needs to display a form to create a new paste. It should always be available at &lt;code&gt;'/'&lt;/code&gt;, the application root.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;get '/' do
  erb :new
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tells Sinatra that when a &lt;span class="caps"&gt;GET&lt;/span&gt; request for &lt;code&gt;'/'&lt;/code&gt; comes in, that we should use the erb helper to render the &lt;em&gt;new.erb&lt;/em&gt; template, which is stored in the &lt;code&gt;views/&lt;/code&gt; subdirectory by convention and marked up with embedded Ruby (ERb). We can render our responses inline as well, which works for dirt-simple applications, but in most cases you&amp;#8217;ll prefer to keep the view templates outside of this file.&lt;/p&gt;
&lt;p&gt;In any case, the &lt;code&gt;new.erb&lt;/code&gt; template is shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class="snippet"&amp;gt;
  &amp;lt;form action="/" method="POST"&amp;gt;
    &amp;lt;textarea name="snippet_body" id="snippet_body" rows="20"&amp;gt;&amp;lt;/textarea&amp;gt;
    &amp;lt;br/&amp;gt;&amp;lt;input type="submit" value="Save"/&amp;gt;
  &amp;lt;/form&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;The Create Action&lt;/h5&gt;
&lt;p&gt;Our next action is analogous to a &lt;code&gt;#create&lt;/code&gt; action in RESTful Rails. The action is requested by a &lt;span class="caps"&gt;POST&lt;/span&gt; to the application root. Sinatra supports the standard &lt;span class="caps"&gt;GET&lt;/span&gt; and &lt;span class="caps"&gt;POST&lt;/span&gt; &lt;span class="caps"&gt;HTTP&lt;/span&gt; methods as well as &lt;span class="caps"&gt;PUT&lt;/span&gt; and &lt;span class="caps"&gt;DELETE&lt;/span&gt;, meaning that you can build 100% RESTful applications with it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;post '/' do
  @snippet = Snippet.new(:body =&amp;gt; params[:snippet_body])
  if @snippet.save
    redirect "/#{@snippet.id}"
  else
    redirect '/'
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty standard stuff, right? We retrieve the parameter passed to us from the new paste form, instantiate a new model and try to save it. If the validations pass, we redirect to the &lt;code&gt;#show&lt;/code&gt; action equivalent. If not, we&amp;#8217;re just going to dump you back to the &lt;code&gt;#new&lt;/code&gt; form again. Since the only way the action will fail is if the &lt;code&gt;body&lt;/code&gt; property is empty, we&amp;#8217;re not going to bother with any sort of error message at this time. We&amp;#8217;re not rendering anything here (merely redirecting), so no template is required.&lt;/p&gt;
&lt;h5&gt;The Show Action / Show Me The Snippets!&lt;/h5&gt;
&lt;p&gt;If our post is successful, we&amp;#8217;re going to be taken to the &lt;code&gt;#show&lt;/code&gt; action, which lives at &lt;code&gt;/:id&lt;/code&gt;, where &lt;code&gt;:id&lt;/code&gt; is the primary key of the corresponding database record. This action will also get accessed directly when you paste that &lt;span class="caps"&gt;URL&lt;/span&gt; to the chat room, and people click to view your code.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;get '/:id' do
  @snippet = Snippet.get(params[:id])
  if @snippet
    erb :show
  else
    redirect '/'
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the code listing above, we look up the particular snippet specified in &lt;code&gt;params[:id]&lt;/code&gt; and set an instance variable by calling DataMapper&amp;#8217;s &lt;code&gt;get&lt;/code&gt; method (equivalent to Active Record&amp;#8217;s &lt;code&gt;find&lt;/code&gt; and one of many ways to do record lookups with DataMapper). If the &lt;code&gt;@snippet&lt;/code&gt; is not found we&amp;#8217;ll redirect back to the new snippet form. Otherwise we render an ERb template, which of course has access to that instance variable. Here&amp;#8217;s the code you&amp;#8217;ll want in &lt;code&gt;/views/show.erb&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class="snippet"&amp;gt;
  &amp;lt;div class="sbody" id="content"&amp;gt;&amp;lt;%= @snippet.formatted_body %&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div class="sdate"&amp;gt;Created on &amp;lt;%= @snippet.created_at.strftime("%B %d, %Y at %I:%M %p") %&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;br/&amp;gt;&amp;lt;a href="/"&amp;gt;New Paste!&amp;lt;/a&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;The Layout&lt;/h5&gt;
&lt;p&gt;We&amp;#8217;re pretty much done at this point. However, to dress up our output we&amp;#8217;ll use an ERb layout template with some &lt;span class="caps"&gt;CSS&lt;/span&gt; to handle the syntax highlighting that Syntaxi provides for us. If it exists, Sinatra will render a special view template (just like Rails does) named &lt;code&gt;layout.erb&lt;/code&gt; in the &lt;code&gt;views/&lt;/code&gt; subdirectory. This layout will be used to wrap the output of the other views rendered when the &lt;code&gt;erb&lt;/code&gt; helper method is called.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;
&amp;lt;html xmlns="http://www.w3.org/1999/xhtml"&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;title&amp;gt;&amp;lt;%= @title || 'Toopaste!' %&amp;gt;&amp;lt;/title&amp;gt;
  &amp;lt;style&amp;gt;
    html {
      background-color: #eee;
    }
    .snippet {
      margin: 5px;
    }
    .snippet textarea, .snippet .sbody {
      border: 5px dotted #eee;
      padding: 5px;
      width: 700px;
      color: #fff;
      background-color: #333;
    }
    .snippet textarea {
      padding: 20px;
    }
    .snippet input, .snippet .sdate {
      margin-top: 5px;
    }&lt;/code&gt;

&lt;code&gt;    /* Syntax highlighting */
    #content .syntax_ruby .normal {}
    #content .syntax_ruby .comment { color: #CCC; font-style: italic; border: none; margin: none; }
    #content .syntax_ruby .keyword { color: #C60; font-weight: bold; }
    #content .syntax_ruby .method { color: #9FF; }
    #content .syntax_ruby .class { color: #074; }
    #content .syntax_ruby .module { color: #050; }
    #content .syntax_ruby .punct { color: #0D0; font-weight: bold; }
    #content .syntax_ruby .symbol { color: #099; }
    #content .syntax_ruby .string { color: #C03; }
    #content .syntax_ruby .char { color: #F07; }
    #content .syntax_ruby .ident { color: #0D0; }
    #content .syntax_ruby .constant { color: #07F; }
    #content .syntax_ruby .regex { color: #B66; }
    #content .syntax_ruby .number { color: #FF0; }
    #content .syntax_ruby .attribute { color: #7BB; }
    #content .syntax_ruby .global { color: #7FB; }
    #content .syntax_ruby .expr { color: #909; }
    #content .syntax_ruby .escape { color: #277; }
    #content .syntax {
      background-color: #333;
      padding: 2px;
      margin: 5px;
      margin-left: 1em;
      margin-bottom: 1em;
    }
    #content .syntax .line_number {
      text-align: right;
      font-family: monospace;
      padding-right: 1em;
      color: #999;
    }
  &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;%= yield %&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Hallo Pastie!&lt;/h4&gt;
&lt;p&gt;You can fire up your new Sinatra and DataMapper-powered application by issuing the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ruby toopaste.rb
== Sinatra has taken the stage on port 4567!&lt;/code&gt;

&lt;code&gt;Sinatra sits on top of &amp;lt;a href="http://mongrel.rubyforge.org/"&amp;gt;Mongrel&amp;lt;/a&amp;gt; by default, making it super-easy to use (and thread-safe to boot!). If you open up a web browser and point it at &amp;lt;code&amp;gt;http://localhost:4567&amp;lt;/code&amp;gt; you'll see the results. Copy and paste away. You now have a fully functional (albeit slightly retarded) pastie clone with  syntax highlighting for Ruby code snippets. And the core logic is all contained in a single file, with a few external ERb templates for cleanliness.&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Wrapping Up&lt;/h4&gt;
&lt;p&gt;As we mentioned earlier, Sinatra is based on top of Rack which means you can deploy it in a number of ways. It&amp;#8217;s incredibly useful for lots of quick tasks and is definitely my &amp;#8220;micro framework&amp;#8221; of choice at the moment. DataMapper is well, just awesome. What else can I say? Lots of &lt;a href="http://merbivore.com"&gt;Merb&lt;/a&gt; developers already know this, of course.&lt;/p&gt;
&lt;p&gt;OK enough blathering for now. Longest blog post. Ever. If you like, you can &lt;a href="http://paste.zerosum.org"&gt;play with the finished app&lt;/a&gt; or &lt;a href="http://github.com/zapnap/toopaste"&gt;check out the sources on GitHub&lt;/a&gt;. Enjoy, and please comment if you have any problems or suggestions for improvements. This code was written and tested on OS X 10.5 and Debian Etch. Special thanks to Jonathan Stott for the early review and fact checking.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Radiant Scoped Multi Update</title>
   <link href="http://blog.zerosum.org/2008/6/24/radiant-scoped-multi-update.html" />
   <published>2008-06-24T00:00:00-04:00</published>
   <updated>2008-06-24T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/6/24/radiant-scoped-multi-update</id>
   <content type="html">&lt;p&gt;Blog updates have been pretty infrequent lately. As have my &lt;span class="caps"&gt;OSS&lt;/span&gt; contributions. Sorry! I haven&amp;#8217;t had an awful lot of spare. Between client work and wrapping up my book (more on that soon), things have been a bit&amp;#8230; insane.&lt;/p&gt;
&lt;p&gt;However, I did find some time over the weekend to finally update the &lt;a href="http://github.com/zapnap/radiant-multi-site-extension"&gt;scoped multi-site Radiant extension fork&lt;/a&gt; to work with 0.6.7 and latest edge.&lt;/p&gt;
&lt;p&gt;Note that the old &lt;span class="caps"&gt;URL&lt;/span&gt; is no longer accessible, as the &lt;a href="http://github.com/radiant"&gt;Radiant&lt;/a&gt; Github presence was recently refactored to remove extensions from the core project repo.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>I'm Back</title>
   <link href="http://blog.zerosum.org/2008/6/3/i-m-back.html" />
   <published>2008-06-03T00:00:00-04:00</published>
   <updated>2008-06-03T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/6/3/i-m-back</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m back on the east coast after a 1.5 week west coast mini-tour, culminating with Railsconf information overload and a couple of great parties. I&amp;#8217;ve written up some session highlights over at &lt;span class="caps"&gt;DDJ&lt;/span&gt; (parts &lt;a href="http://dobbscodetalk.com/index.php?option=com_myblog&amp;show=Railsconf-Highlights-Part-I-482.html&amp;Itemid=29"&gt;one&lt;/a&gt; and &lt;a href="http://dobbscodetalk.com/index.php?option=com_myblog&amp;show=Railsconf-Highlights-Part-II.html&amp;Itemid=29"&gt;two&lt;/a&gt;) in case you&amp;#8217;re interested.&lt;/p&gt;
&lt;p&gt;Greets to all the fine folks I met at the conference, especially the Offrails crew and &lt;a href="http://offtheline.net/"&gt;Jason LaPier&lt;/a&gt;, my local guide to Portland nightlife and microbrews (also a badass Rails developer who was recently published in Pragprog&amp;#8217;s &lt;i&gt;Advanced Rails Recipes&lt;/i&gt;). Thanks dude!&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;ve sent an email and I haven&amp;#8217;t gotten back to you yet, my apologies; I&amp;#8217;m still a bit jetlagged and trying to catch up on a ton of things.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Travel Plans</title>
   <link href="http://blog.zerosum.org/2008/5/20/travel-plans.html" />
   <published>2008-05-20T00:00:00-04:00</published>
   <updated>2008-05-20T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/5/20/travel-plans</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve got my itinerary planned out for &lt;a href="http://www.railsconf.com"&gt;Railsconf&lt;/a&gt;. I&amp;#8217;ll also be hitting up a couple other west coast cities before landing in Portland. First stop is SF to visit my friend Ankit on Friday. Then trekking up to Eugene on the Amtrak Coast Starlite (I love me my trains) late night Sunday to hang and brainstorm with our designer/big-thinker Ty for a few days. Then it&amp;#8217;s off to Portland on Thursday.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re in any one of those cities and want to grab a beer (or a smoothie), hit me up on &lt;a href="http://twitter.com/zapnap"&gt;Twitter&lt;/a&gt;. Hopefully I&amp;#8217;ll see some of you at Railsconf.&lt;/p&gt;
&lt;p&gt;Also, I&amp;#8217;ll be giving a talk at &lt;a href="http://blog.zenlinux.com/?p=163"&gt;NHRuby tonight&lt;/a&gt; (5/20) on &lt;a href="http://rack.rubyforge.org"&gt;Rack&lt;/a&gt;. If you&amp;#8217;re in the area, stop by.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Random Passenger Observations</title>
   <link href="http://blog.zerosum.org/2008/5/5/random-passenger-observations.html" />
   <published>2008-05-05T00:00:00-04:00</published>
   <updated>2008-05-05T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/5/5/random-passenger-observations</id>
   <content type="html">&lt;p&gt;Played around with &lt;a href="http://www.modrails.com"&gt;Passenger&lt;/a&gt; (v1.0.4) a bit more last weekend. Deployed a &lt;a href="http://www.radiantcms.org"&gt;Radiant&lt;/a&gt; instance with it for staging. Overall, quite happy. However, thought I&amp;#8217;d take the opportunity to jot down a few observations:&lt;/p&gt;
&lt;p&gt;First, Radiant, with a smattering of extensions, takes a while to start up on the vhost we&amp;#8217;re playing around on (yes, need to pump up those specs before deploying anything real). Since Passenger cleans up idle Rails instances when they fall into disuse, this can mean a harsh initial request delay for infrequently accessed hosts.&lt;/p&gt;
&lt;p&gt;Passenger has clearly targeted the shared host market, where hosts have a large memory footprint and a large number of applications. The same strategy doesn&amp;#8217;t work quite as well for a small &lt;span class="caps"&gt;VPS&lt;/span&gt; memory footprint and a single application root, where it would make sense to keep an instance in memory at all times (and clean it up and respawn it, perhaps, on occasion if an idle timeout is reached).&lt;/p&gt;
&lt;p&gt;The solution in this case is to increase the &lt;a href="http://modrails.com//documentation/Users%20guide.html#_configuring_passenger"&gt;Rails pool idle timeout&lt;/a&gt; to something that matches your traffic profile (of course, the tradeoff there is with the growing memory footprint of long-running processes&amp;#8230;). And while you&amp;#8217;re at it, adjust the maximum number of spawned instances &amp;#8212; it defaults to 20, which is great for a dedicated with 2GB but not so good if you&amp;#8217;re running a single application on a 512MB &lt;span class="caps"&gt;VPS&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;More information is available in the &lt;a href="http://modrails.com//documentation/Architectural%20overview.html"&gt;architectural overview&lt;/a&gt; and the excellent &lt;a href="http://modrails.com//documentation/Users%20guide.html"&gt;user guide&lt;/a&gt; that the Phusion guys have put together. The &lt;a href="http://modrails.com//documentation/rdoc/classes/Passenger/SpawnManager.html"&gt;SpawnManager&lt;/a&gt; itself is written in Ruby, and has a set of &lt;a href="http://modrails.com/documentation/rdoc/index.html"&gt;RDocs&lt;/a&gt; that you might want to take a look at as well.&lt;/p&gt;
&lt;p&gt;We initially had some process ownership issues, where the Rails production log wasn&amp;#8217;t being written to. The Rails server instance is going to be running as whatever user owns config/environment.rb (unless you change this in the config), so make sure to chown/chmod appropriately.&lt;/p&gt;
&lt;p&gt;Finally, the restart mechanism, although a bit odd, is pretty useful. If you touch a file called restart.txt in the #{RAILS_ROOT}/tmp directory, it&amp;#8217;ll reload the application instance on the next request without having to explicitly restart apache. Here&amp;#8217;s a Capistrano deploy:restart task for this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;namespace :deploy do
  task :stop, :roles =&amp;gt; [:app] do
    puts "Use the deploy:restart task to restart the Rails application"
  end
  task :start, :roles =&amp;gt; [:app] do
    puts "Use the deploy:restart task to restart the Rails application"
  end
  task :restart, :roles =&amp;gt; [:app] do
    run "touch #{current_path}/tmp/restart.txt"
  end
end
&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Note To Self (Good Examples Are Hard)</title>
   <link href="http://blog.zerosum.org/2008/5/3/note-to-self.html" />
   <published>2008-05-03T00:00:00-04:00</published>
   <updated>2008-05-03T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/5/3/note-to-self</id>
   <content type="html">&lt;p&gt;The single hardest thing about writing a book, I&amp;#8217;ve decided, isn&amp;#8217;t the writing part. It certainly isn&amp;#8217;t the technical part either. I don&amp;#8217;t mean to downplay my own skills or those of any other technical author, but the truth is that you don&amp;#8217;t have to be a guru to write a fantastic book (it does help, of course).&lt;/p&gt;
&lt;p&gt;The key to writing good book material is being able to show people how to do things while keeping them entertained. That means coming up with examples that tread the line between being &lt;strong&gt;practical&lt;/strong&gt;, being appropriately &lt;strong&gt;demonstrative&lt;/strong&gt;, and being &lt;strong&gt;correct&lt;/strong&gt;. Good examples are the hard part.&lt;/p&gt;
&lt;p&gt;When developing an example, you&amp;#8217;re trying to come up with something that has the following characteristics:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;It&amp;#8217;s interesting.&lt;/strong&gt; That is, it&amp;#8217;s worth writing about in the first place. No one wants to read another blog post creation example (unless there&amp;#8217;s something unusual about it). &lt;span class="caps"&gt;BORING&lt;/span&gt;.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;It represents best practices.&lt;/strong&gt; You&amp;#8217;re an author. You have to be right. Or at least able to competently defend your implementation choices, anyway.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;It illustrates those concepts that you&amp;#8217;re trying to write about.&lt;/strong&gt; This should be first point, rather than third. See what I mean?&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;It minimizes focus on those elements that you are not writing about.&lt;/strong&gt; That is to say, we shouldn&amp;#8217;t spend a lot of time talking about fuzzy bears, even though there are many different types of fuzzy bears, six species of which are listed as vulnerable or endangered by the World Conservation Union (whose headquarters are in the scenic Lake Geneva area of Gland, Switzerland).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="http://blog.zerosum.org/assets/2008/5/3/grizzly_bear.jpg" alt="bears!" style="float: right; margin: 0 0 10px 10px;"/&gt;&lt;/p&gt;
&lt;p&gt;The last point is a tricky one, but it&amp;#8217;s important. You have to cut corners when creating good examples &amp;#8212; but not the important ones or the ones that would prevent it from representing best practices. If you&amp;#8217;re trying to illustrate, for example, how to build a tag cloud, you don&amp;#8217;t want to spend lots of time on the &lt;span class="caps"&gt;CSS&lt;/span&gt; for making it pretty. Leave that to the &lt;span class="caps"&gt;CSS&lt;/span&gt; books.&lt;/p&gt;
&lt;p&gt;If your example involves video transcoding, and the point is to illustrate the use of a message queue, you&amp;#8217;re going to be really tempted to spend an extra 2-3 pages on certain format discrepancies or operational edge cases but DON&amp;#8217;T. It&amp;#8217;s interesting, sure, but if it&amp;#8217;s not central to what you&amp;#8217;re currently trying to demonstrate (message queues). You must resist.&lt;/p&gt;
&lt;p&gt;If your example is a simple web service for sharing geographic location data and you&amp;#8217;re using a bunch of RESTful conventions, make sure to explain the basic concepts. But don&amp;#8217;t write a dissertation on &lt;span class="caps"&gt;REST&lt;/span&gt; vs &lt;span class="caps"&gt;SOAP&lt;/span&gt;. And don&amp;#8217;t worry about responding to formats that aren&amp;#8217;t part of the main example.&lt;/p&gt;
&lt;p&gt;Just because it&amp;#8217;s how you&amp;#8217;d do it in a real-life project doesn&amp;#8217;t mean it&amp;#8217;s how you&amp;#8217;d write about it or explain it to others. Keep it simple, lively, and (as Gold Five so succinctly put it before crashing his X-Wing) stay on target.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Music To Code By</title>
   <link href="http://blog.zerosum.org/2008/4/18/music-to-code-by.html" />
   <published>2008-04-18T00:00:00-04:00</published>
   <updated>2008-04-18T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/4/18/music-to-code-by</id>
   <content type="html">&lt;p&gt;There&amp;#8217;s a good thread going on over at &lt;a href="http://news.ycombinator.com/item?id=167076"&gt;Hacker News&lt;/a&gt; today regarding music for coding sprints. It&amp;#8217;s interesting to see that a number of people, like me, have trouble concentrating when listening to music with prominent lyrics, whereas others thrive on it.&lt;/p&gt;
&lt;p&gt;A lot of people also seem to really dig electronica. I guess that&amp;#8217;s no big surprise. It&amp;#8217;s never done much for me, personally, although there are a few electronic pieces I do really like (NIN&amp;#8217;s &lt;em&gt;Ghosts&lt;/em&gt; being a recent example). Being an ex-hc/metalhead I gravitate more towards melodic post-rock stuff and the occasional poppy masterpiece.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s some stuff in my current work playlist:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Explosions in the Sky&lt;/li&gt;
	&lt;li&gt;Mogwai&lt;/li&gt;
	&lt;li&gt;Castor&lt;/li&gt;
	&lt;li&gt;My Bloody Valentine&lt;/li&gt;
	&lt;li&gt;Elliott&lt;/li&gt;
	&lt;li&gt;Pinback&lt;/li&gt;
	&lt;li&gt;Isis&lt;/li&gt;
	&lt;li&gt;On The Might of Princes&lt;/li&gt;
	&lt;li&gt;Jesu&lt;/li&gt;
	&lt;li&gt;Portishead&lt;/li&gt;
	&lt;li&gt;Dredg&lt;/li&gt;
	&lt;li&gt;National Skyline&lt;/li&gt;
	&lt;li&gt;Pelican&lt;/li&gt;
	&lt;li&gt;Low Frequency In Stereo&lt;/li&gt;
	&lt;li&gt;Radiohead&lt;/li&gt;
	&lt;li&gt;There Were Wires&lt;/li&gt;
	&lt;li&gt;Godspeed You! Black Emperor&lt;/li&gt;
	&lt;li&gt;Mouth of the Architect&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Yes I know some of these bands have lyrics. But they&amp;#8217;re so fuzzed up or unintelligible that my brain doesn&amp;#8217;t seem to process them while working, so all is good. And in the case of bands like Elliott and Pinback and Dredg, the vocals are prominent but somehow almost feel like more of an instrument. Also seems to work. Kind of strange, I guess.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>NHRuby Hackfest</title>
   <link href="http://blog.zerosum.org/2008/4/14/nhruby-hackfest.html" />
   <published>2008-04-14T00:00:00-04:00</published>
   <updated>2008-04-14T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/4/14/nhruby-hackfest</id>
   <content type="html">&lt;p&gt;Yep, that&amp;#8217;s right. &lt;a href="http://wiki.nhruby.org/index.php/Upcoming_meetings"&gt;Hackfest tomorrow night&lt;/a&gt; in Portsmouth. Bring any code you&amp;#8217;re having issues with. Failing that, I&amp;#8217;ve got a couple project tickets (DataMapper, Radiant) that we can dig into. We&amp;#8217;ll spend 30 minutes or so on a quickie mod_rails demo while we&amp;#8217;re there too.&lt;/p&gt;
&lt;p&gt;In other local news, John Herman has been swell enough to put together an &lt;a href="http://nhmediamakers.wordpress.com/2008/04/08/hello-world/"&gt;NH Media Makers&lt;/a&gt; group. The first get-together is May 11th at Crackskulls in Newmarket. Rock out.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Mod_Rails Revealed</title>
   <link href="http://blog.zerosum.org/2008/4/12/mod_rails-revealed.html" />
   <published>2008-04-12T00:00:00-04:00</published>
   <updated>2008-04-12T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/4/12/mod_rails-revealed</id>
   <content type="html">&lt;p&gt;The hardworking hackers over at Phusion finally unveiled &lt;a href="http://www.modrails.com"&gt;Passenger&lt;/a&gt; (mod_rails) earlier today. I just moved one of our staging servers over to it and will be playing around with it a bit more over the weekend. So far I&amp;#8217;m happy to report that, as advertised, it&amp;#8217;s dead easy to use&amp;#8230; and the performance seems solid.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;d write up a tutorial but honestly it&amp;#8217;s so simple that it&amp;#8217;s completely unnecessary (imagine that!). Check out the &lt;a href="http://www.modrails.com/videos/passenger.mov"&gt;updated screencast&lt;/a&gt; for all you need to know to get up and running and make sure to dig into the provided docs if you need more. They&amp;#8217;re very thorough.&lt;/p&gt;
&lt;p&gt;In summary, it&amp;#8217;s great to see more Rails deployment options emerging, and it&amp;#8217;ll be interesting to see viable shared hosting options for the low-end market too. Although I&amp;#8217;m a strong believer in the app server + frontend web server pairing, there are a whole class of applications for which it just seems like overkill.&lt;/p&gt;
&lt;p&gt;A hearty &amp;#8216;nice work&amp;#8217; to everyone involved! Now where&amp;#8217;s my mod_rack? :-)&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span class="caps"&gt;UPDATED&lt;/span&gt; 4/12&lt;/b&gt;: this blog is now running on mod_rails and Mephisto 0.8!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>2008 Rails Rumble Rumors</title>
   <link href="http://blog.zerosum.org/2008/4/10/2008-rails-rumble-rumors.html" />
   <published>2008-04-10T00:00:00-04:00</published>
   <updated>2008-04-10T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/4/10/2008-rails-rumble-rumors</id>
   <content type="html">&lt;p&gt;Just to clear up any possible confusion on that matter: Yes. There will be a &lt;a href="http://www.railsrumble.com"&gt;2008 Rails Rumble&lt;/a&gt;. And no. It will not be in May. Probably September or October.&lt;/p&gt;
&lt;p&gt;We have a lot of great ideas (thanks to everyone that participated and commented) that will improve on last year&amp;#8217;s experience dramatically and the whole team is looking forward to it, in a big way. More information coming soon, I promise, as well as an announcement, new blog, and specific details prior to Railsconf.&lt;/p&gt;
&lt;p&gt;Oh, and speaking of Railsconf&amp;#8230; Josh Owens, of &lt;a href="http://tastyplanner.com"&gt;TastyPlanner&lt;/a&gt; fame (last year&amp;#8217;s grand prize winner), is giving what looks to be a fun talk about their &lt;a href="http://en.oreilly.com/rails2008/public/schedule/detail/1935"&gt;experience building a kickass app in a 48 hour timeframe&lt;/a&gt;. If you&amp;#8217;re going to be there, you ought to check it out. Especially if you&amp;#8217;re interested in participating this year. If you haven&amp;#8217;t yet registered for the conference, you&amp;#8217;re &lt;a href="http://weblog.rubyonrails.org/2008/4/7/session-schedule-for-railsconf-available"&gt;running out of time&lt;/a&gt;, so get to it.&lt;/p&gt;
&lt;p&gt;See you there!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Radiant Super Multi Go!</title>
   <link href="http://blog.zerosum.org/2008/4/3/radiant-super-multi.html" />
   <published>2008-04-03T00:00:00-04:00</published>
   <updated>2008-04-03T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/4/3/radiant-super-multi</id>
   <content type="html">&lt;p&gt;Here at Ubikorp we&amp;#8217;ve used &lt;a href="http://www.radiantcms.org"&gt;Radiant&lt;/a&gt; as the basis for a number of client projects who needed core &lt;span class="caps"&gt;CMS&lt;/span&gt;-like functionality. As anyone who&amp;#8217;s played with it knows, Radiant is very barebones; this is intentional and a welcome change from most packages, which attempt to throw the kitchen sink of clutter at each and every problem. Fortunately, it&amp;#8217;s easy to build on top of the basics by using a well thought-out extensions system &amp;#8212; there are a large number of stock &lt;a href="http://wiki.radiantcms.org/Thirdparty_Extensions"&gt;extensions&lt;/a&gt; available (and it&amp;#8217;s also really easy to roll your own for custom app logic).&lt;/p&gt;
&lt;p&gt;One of the more interesting extensions is the &lt;a href="http://svn.radiantcms.org/radiant/trunk/extensions/multi_site/"&gt;multi-site extension&lt;/a&gt;. To be honest, multi-site capability is something I really feel should be a core feature, but since it&amp;#8217;s not, this approach works surprisingly well (at least until you start adding other extensions that would ideally be multi-site-aware). Radiant school headmaster Sean Cribbs wrote an initial version of the extension back in November, but it didn&amp;#8217;t quite work for us on a particular project &amp;#8212; we needed to be able to scope individual user-level access to particular sites. So we extended it, and thus the scoped multi-site extension was born.&lt;/p&gt;
&lt;p&gt;Well, actually, it&amp;#8217;s just a fork of the multi-site plugin. For now.&lt;/p&gt;
&lt;p&gt;Features:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;scopes user level access to individual sites (admins and developers still have access to all sites)&lt;/li&gt;
	&lt;li&gt;regular users can&amp;#8217;t see, edit, or access other user sites that they don&amp;#8217;t own&lt;/li&gt;
	&lt;li&gt;optionally scopes layouts to sites&lt;/li&gt;
	&lt;li&gt;snippets usable everywhere, but display and editing of snippets limited to admins/developers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anyway, if you&amp;#8217;re interested in seeing our changes you can check it out on &lt;a href="http://github.com/zapnap/radiant/tree/master/extensions/multi_site"&gt;github&lt;/a&gt; in my fork of Sean&amp;#8217;s Radiant repo. Is this a candidate for integration into the existing extension, or should we spin it out as a separate extension? Let me know what you think.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span class="caps"&gt;UPDATED&lt;/span&gt; 6/24:&lt;/b&gt; The &lt;span class="caps"&gt;URL&lt;/span&gt; is out of date. See &lt;a href="http://blog.zerosum.org/2008/6/24/radiant-scoped-multi-update"&gt;this blog post&lt;/a&gt; for more details and updates (the latest version requires Radiant 0.6.7 or later).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Twittering</title>
   <link href="http://blog.zerosum.org/2008/4/2/twittering.html" />
   <published>2008-04-02T00:00:00-04:00</published>
   <updated>2008-04-02T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/4/2/twittering</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been bitten by the &lt;a href="http://www.twitter.com"&gt;Twitter&lt;/a&gt; bug. I know, I&amp;#8217;m a little late to the party. But being late is fashionable. And I sure like the fashion.&lt;/p&gt;
&lt;p&gt;Anyway, go ahead and &lt;a href="http://www.twitter.com/zapnap"&gt;stalk me&lt;/a&gt;. If you dare. Or check out the status updates in the blog sidebar if that&amp;#8217;s what you&amp;#8217;re into. I&amp;#8217;ve also added my &lt;a href="http://dobbscodetalk.com"&gt;&lt;span class="caps"&gt;DDJ&lt;/span&gt;&lt;/a&gt; blog feed to the sidebar. A couple of my recent articles:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://dobbscodetalk.com/index.php?option=com_myblog&amp;show=Roll-Your-Own-Ruby-Web-Framework.html&amp;Itemid=29"&gt;Roll Your Own Web Framework&lt;/a&gt; (an introduction to Rack)&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://dobbscodetalk.com/index.php?option=com_myblog&amp;show=Vendor-Everything-Just-Got-Easier.html&amp;Itemid=29"&gt;Rails: Vendor Everything Just Got Easier&lt;/a&gt; (the new config.gem features in Rails Edge)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More soon. Promise.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Mod_Rails Teaser</title>
   <link href="http://blog.zerosum.org/2008/3/20/mod_rails.html" />
   <published>2008-03-20T00:00:00-04:00</published>
   <updated>2008-03-20T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/3/20/mod_rails</id>
   <content type="html">&lt;p&gt;Well, &lt;a href="http://www.modrails.com"&gt;this&lt;/a&gt; is sure to stir up some buzz in the Rubyverse&amp;#8230;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>DDJ Code Talk Launches</title>
   <link href="http://blog.zerosum.org/2008/3/15/ddj-code-talk-launches.html" />
   <published>2008-03-15T00:00:00-04:00</published>
   <updated>2008-03-15T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2008/3/15/ddj-code-talk-launches</id>
   <content type="html">&lt;p&gt;The legendary &lt;a href="http://www.ddj.com"&gt;Dr Dobb&amp;#8217;s Journal&lt;/a&gt; just announced the launch of their new blog and forum system, &lt;a href="http://www.ddj.com/blog/portal/archives/2008/03/dr_dobbs_code_t.html"&gt;&lt;span class="caps"&gt;DDJ&lt;/span&gt; Code Talk&lt;/a&gt;. I was extremely honored when Jon asked me to contribute, as &lt;span class="caps"&gt;DDJ&lt;/span&gt; has long been one of my favorite industry pubs. Them peoples is hardcore.&lt;/p&gt;
&lt;p&gt;In the coming months I&amp;#8217;ll be contributing articles about Ruby, web application development, and lightweight languages. Head on over to check out my first article for them, a quick survey of &lt;a href="http://www.dobbscodetalk.com/index.php?option=com_myblog&amp;show=test.html&amp;Itemid=29"&gt;Alternative Ruby Web Frameworks&lt;/a&gt;. There are a few other Ruby geeks hiding in their trees too, and a broad range of topics, including Python, Java, .&lt;span class="caps"&gt;NET&lt;/span&gt;, D (!), databases and web service architecture and design. Thanks for reading!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>NHRuby: Django/Rails</title>
   <link href="http://blog.zerosum.org/2008/3/9/nhruby-django-rails.html" />
   <published>2008-03-09T00:00:00-05:00</published>
   <updated>2008-03-09T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/3/9/nhruby-django-rails</id>
   <content type="html">&lt;p&gt;If you&amp;#8217;re in the ME/NH/MA area on Tuesday, make sure to stop by the &lt;a href="http://wiki.nhruby.org/index.php/Upcoming_meetings"&gt;NH Ruby &lt;span class="caps"&gt;SIG&lt;/span&gt;&lt;/a&gt;; &lt;a href="http://brianturnbull.com/"&gt;Brian Turnbull&lt;/a&gt; will be presenting an in-depth talk comparing the philosophies of Rails and Django. I&amp;#8217;ve never done any Python work at all myself, so I&amp;#8217;m really looking forward to this dissection.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re not in the area, you&amp;#8217;re still in luck. We&amp;#8217;re trying something new this month, and will be &lt;a href="http://wiki.nhruby.org/index.php/Upcoming_meetings"&gt;broadcasting the event live via WebEx&lt;/a&gt;. Big thanks to &lt;a href="http://www.timgolden.com/"&gt;Tim Golden&lt;/a&gt; and our sponsor &lt;a href="http://rmcres.com"&gt;&lt;span class="caps"&gt;RMC&lt;/span&gt; Research&lt;/a&gt; for hooking this up!&lt;/p&gt;
&lt;p&gt;(&lt;span class="caps"&gt;NOTE&lt;/span&gt;: we usually meet on the third Tuesday of the month, but our host had some scheduling problems this time around; we&amp;#8217;ll be returning to the normal schedule in April)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Git Ur Radiant Extensions</title>
   <link href="http://blog.zerosum.org/2008/3/5/git-ur-radiant-extensions.html" />
   <published>2008-03-05T00:00:00-05:00</published>
   <updated>2008-03-05T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/3/5/git-ur-radiant-extensions</id>
   <content type="html">&lt;p&gt;I published a new &lt;a href="http://radiantcms.org"&gt;Radiant&lt;/a&gt; extension yesterday: &lt;a href="http://github.com/zapnap/database_form"&gt;Database Form&lt;/a&gt;. It provides a new page type and tags for constructing contact and request info forms and will save user responses to a database table. Those responses can then be exported for use in another application (&lt;span class="caps"&gt;CRM&lt;/span&gt;, etc). See the &lt;span class="caps"&gt;README&lt;/span&gt; for usage and examples. It was extracted from some client work that we&amp;#8217;ll be deploying soon.&lt;/p&gt;
&lt;p&gt;If this sounds good, you can download or clone it from &lt;a href="http://github.com/zapnap/database_form"&gt;GitHub&lt;/a&gt;. While you&amp;#8217;re there, spend a few minutes poking around; GitHub is pretty dang cool. They&amp;#8217;ve definitely succeeded in making Git repository hosting stupid simple. Just click a button to create a project, follow a few commands on your local system to import your sources, and you&amp;#8217;re off and running. You can then view the repo history, browse the source, see diffs, download a tarball (for easy extension installation in your pre-existing Radiant project), and fork it if you want to add your own features. That&amp;#8217;s where things get sweet, of course: Fork the project, make some changes, and send me a pull request so we can merge them into the master branch. All this is possible without GitHub, but it sure does a swell job of streamlining things and abstracting the suck away.&lt;/p&gt;
&lt;p&gt;It also exposes the links between developers and their project contributions in a pretty cool way. See the &lt;a href="http://github.com/sam/dm/network"&gt;DataMapper&lt;/a&gt; project&amp;#8217;s &amp;#8220;network&amp;#8221; page to see what I&amp;#8217;m talking about. &lt;a href="http://tomayko.com/weblog/2008/02/26/github-is-myspace-for-hackers"&gt;Ryan Tomayko&lt;/a&gt; has pointed out that this sort of interaction starts to smell an awful lot like a MySpace for developers, where lines in the social graph are drawn based on &lt;span class="caps"&gt;OSS&lt;/span&gt; project work. Wow, that&amp;#8217;s a cool thought, ain&amp;#8217;t it?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Principle of Least Surprise</title>
   <link href="http://blog.zerosum.org/2008/3/4/principle-of-least-surprise.html" />
   <published>2008-03-04T00:00:00-05:00</published>
   <updated>2008-03-04T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/3/4/principle-of-least-surprise</id>
   <content type="html">&lt;p&gt;One of the things I love about Ruby is that it tends to follow &lt;a href="http://en.wikipedia.org/wiki/Principle_of_least_astonishment"&gt;the principle of least surprise&lt;/a&gt;; things just work the way you would expect them to, with precious few exceptions (cough cough &lt;a href="http://www.ruby-doc.org/core/classes/Enumerable.html#M003160"&gt;inject&lt;/a&gt; cough). Horray for intuitiveness.&lt;/p&gt;
&lt;p&gt;On the other hand, I&amp;#8217;ve become so spoiled by The Principle that willful violations stand out like the sober guy at the all-inclusive beach resort. I know I&amp;#8217;m being a nitpicky ass here, but &lt;a href="http://dev.rubyonrails.org/ticket/11119"&gt;this Rails bug^H^H^H ticket&lt;/a&gt; makes me kinda ill. Funny, because in my previous life as a Java/&lt;span class="caps"&gt;PHP&lt;/span&gt; developer, I wouldn&amp;#8217;t have even batted an eyelash at it.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>OpenID + Client Certs = Win</title>
   <link href="http://blog.zerosum.org/2008/2/22/openid-client-certificates-win.html" />
   <published>2008-02-22T00:00:00-05:00</published>
   <updated>2008-02-22T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/2/22/openid-client-certificates-win</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m a big fan of &lt;a href="http://openid.net/"&gt;OpenID&lt;/a&gt;. Or rather, I&amp;#8217;m a big fan of what OpenID and &lt;a href="http://www.dataportability.org"&gt;data portability&lt;/a&gt; mean for the web at large in the coming white days. Single sign on and distributed identity is certainly an idea that&amp;#8217;s been long overlooked and it&amp;#8217;s time that we changed that. The next time you write a web application, ask yourself: &amp;#8220;do my users really need yet another set of login credentials?&amp;#8221;. Then implement OpenID. It&amp;#8217;s really simple, especially in Rails. I gave a presentation on it at &lt;a href="http://wiki.nhruby.org"&gt;NHRuby&lt;/a&gt; last month (&lt;a href="http://wiki.nhruby.org/index.php/Past_meetings"&gt;download &lt;span class="caps"&gt;PDF&lt;/span&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;So, as gah-gah as I am over single sign on for ease of use, I&amp;#8217;m a embarrassed to note that, like almost everyone else, I&amp;#8217;ve completely overlooked &lt;a href="http://wiki.cacert.org/wiki/ClientCerts"&gt;client certificates&lt;/a&gt; for web-based authentication. By using client certificates you one-up single sign on by removing the need to use a login/password at all. This isn&amp;#8217;t new; it&amp;#8217;s something that&amp;#8217;s been available in every web browser for pretty much as long as anyone can remember. And yet I&amp;#8217;ve never, ever seen a site that supports them for an authentication mechanism. Sad faces abound.&lt;/p&gt;
&lt;p&gt;But wait! OpenID to the rescue! It turns out that &lt;a href="http://myopenid.com"&gt;MyOpenID&lt;/a&gt; (and a host of other OpenID providers) DO make use of them. So if you create a client certificate with your OpenID provider, you can eliminate the need to use a login/pass with any OpenID client sites. Cheers to &lt;a href="http://drnicwilliams.com/2008/02/22/zero-sign-on-with-client-certificates/"&gt;Dr Nic Williams&lt;/a&gt; for digging this up. Sometimes old (and ignored) is the new new. Rock on.&lt;/p&gt;
&lt;p&gt;More details at &lt;a href="http://drnicwilliams.com/2008/02/22/zero-sign-on-with-client-certificates/"&gt;Dr Nic&amp;#8217;s blog&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Plugins Are Unnecessary</title>
   <link href="http://blog.zerosum.org/2008/2/20/plugins-are-unnecessary.html" />
   <published>2008-02-20T00:00:00-05:00</published>
   <updated>2008-02-20T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/2/20/plugins-are-unnecessary</id>
   <content type="html">&lt;p&gt;Plugins really &lt;strong&gt;are&lt;/strong&gt; unnecessary &amp;#8212; &lt;a href="http://blog.jayfields.com/2008/02/shared-ruby-code.html"&gt;Jay Fields is absolutely right&lt;/a&gt;. RubyGems is a great package management system and there&amp;#8217;s no reason it can&amp;#8217;t do double duty here, if we just impose a few extra restrictions on Gem/Plugin structure. There are other benefits too using &lt;a  href="http://www.rubygems.org"&gt;Gems&lt;/a&gt; too, such as versioning and dependency management, which is somewhat painful in the world of Rails plugins.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.merbivore.com"&gt;Merb&lt;/a&gt; already uses Gems for plugins/extensions. Why doesn&amp;#8217;t Rails? Historic reasons, most likely. Rails itself predates the existence of Gems iirc. But seriously, how hard would it be to rewrite `script/plugin` to install a gem and unpack it into `vendor`? That&amp;#8217;s the first step.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>ActiveRecord: Importing YAML</title>
   <link href="http://blog.zerosum.org/2008/2/20/activerecord-importing-yaml.html" />
   <published>2008-02-20T00:00:00-05:00</published>
   <updated>2008-02-20T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/2/20/activerecord-importing-yaml</id>
   <content type="html">&lt;p&gt;Backing up ActiveRecord models to &lt;a href="http://www.ruby-doc.org/core/classes/YAML.html"&gt;&lt;span class="caps"&gt;YAML&lt;/span&gt;&lt;/a&gt; is easy to do, and can be convenient for creating &amp;#8216;templates&amp;#8217; that can later be imported to restore basic project structure in a new database. However, the import process can be a little tricky, as the instantiated objects don&amp;#8217;t seem to respond correctly to `new_record?`&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s what our &lt;span class="caps"&gt;YAML&lt;/span&gt; might look like. Note that it&amp;#8217;s a serialized `CustomWidget`, which is an ActiveRecord model that inherits from `ActiveRecord::Base`.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;--- &lt;/code&gt;

&lt;code&gt;- !ruby/object:CustomWidget 
  attributes: 
    name: DoSomething
    updated_at: 2008-01-28 05:02:54
    description: Does something.
    created_at: 2008-01-28 05:02:54
  attributes_cache: {}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can automatically instantiate the appropriate Ruby objects from this using the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class CustomWidget &amp;lt; ActiveRecord::Base
end&lt;/code&gt;

&lt;code&gt;YAML::add_private_type("CustomWidget") do |type, value|
  CustomWidget.new(value)
end&lt;/code&gt;

&lt;code&gt;obj = YAML::load(File.open("template.yml"))[0]
=&amp;gt; #&amp;lt;CustomWidget name: "DoSomething", created_at: "2008-01-28 05:02:54", updated_at: "2008-01-28 05:02:54", description: "Does something."&amp;gt;
obj.save
=&amp;gt; true&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So what we&amp;#8217;ve done is taken &lt;span class="caps"&gt;YAML&lt;/span&gt; from one project and tried to use it to import the same data into another database (note that IDs are stripped). We define a transfer type for the &lt;span class="caps"&gt;YAML&lt;/span&gt;, providing a mapping to the class, and then we call `&lt;span class="caps"&gt;YAML&lt;/span&gt;::load` to load it up. This returns an array, in this case it contains a single `CustomWidget` object. Everything looks swell. We call `save` on the new object and it returns true.&lt;/p&gt;
&lt;p&gt;However, if we check the `count` of `CustomWidgets` that exist in the database, we&amp;#8217;ll find that it&amp;#8217;s unaltered; no new record has been saved. It turns out that this is because the imported `CustomWidget` doesn&amp;#8217;t report true when `new_record?` is called.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;obj.new_record?
=&amp;gt; nil&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to save itself to the database and get a new ID, the `CustomWidget` instance has to first respond correctly to inquiries as to whether or not it&amp;#8217;s new. We&amp;#8217;d like `new_record?` to return false. The quick-fix secret is to manually toggle the `@new_record` instance variable. If we do that, calling `save` will return true and actually save the object to the database as well this time. Big yay, right?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CustomWidget.count
=&amp;gt; 0
obj.instance_variable_set("@new_record", true)
obj.new_record?
=&amp;gt; true
obj.save
=&amp;gt; true
CustomWidget.count
=&amp;gt; 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yes, this is an ugly hack. Did I say ugly? I meant &lt;em&gt;gross&lt;/em&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Constraint-Driven Development++</title>
   <link href="http://blog.zerosum.org/2008/2/8/constraint-driven-development.html" />
   <published>2008-02-08T00:00:00-05:00</published>
   <updated>2008-02-08T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/2/8/constraint-driven-development</id>
   <content type="html">&lt;p&gt;There was a nice writeup on &lt;a href="http://www.readwriteweb.com/archives/building_web_apps_really_fast.php"&gt;ReadWriteWeb&lt;/a&gt; yesterday about Montreal&amp;#8217;s upcoming &lt;a href="http://www.blitzweekend.com/"&gt;Blitzweekend&lt;/a&gt; event. Like the Rails Rumble that we organized last September, Blitzweekend is another attempt to give people a &amp;#8220;weekend to build a functioning startup from scratch&amp;#8221;. Unlike the Rumble, it isn&amp;#8217;t a competition, and it places added value on physical proximity.&lt;/p&gt;
&lt;p&gt;Josh Catone (of ReadWriteWeb and also RailsForum) dubs this sort of thing &amp;#8220;organized ultra-rapid development&amp;#8221; and notes that, against all odds, this strange weekend-startup phenomenon seems to be trending up. This is really just constraint-based development taken to the next level, and the reason it&amp;#8217;s exciting is simple: it pushes you to deliver results, immediately.&lt;/p&gt;
&lt;p&gt;Results, of course, are what makes application development exciting; seeing a movie get automatically reencoded after upload, a search query produce a number of restaurants in my area, plotted on a map, a transaction get authorized and recorded by the third party &lt;span class="caps"&gt;API&lt;/span&gt; you&amp;#8217;re using. And later, seeing your end to end workflow in place and your first user signup. When we see results, we get motivated to work harder in order to see even more impressive results. When we don&amp;#8217;t see results, we get depressed, we step back, we overthink. Our motivation falters.&lt;/p&gt;
&lt;p&gt;Events and contests like Blitzweekend help give developer-entrepreneurs that extra motivation kick that they often need to get over the motivation speedbump, and an opportunity to gather a team together and just go for it. If you haven&amp;#8217;t tried it, you really should. In the process you&amp;#8217;ll find out if you can work with your team in the long haul, write some (hopefully) great code, and figure out whether or not the idea has legs to stand on. If it does, you&amp;#8217;ll have visible proof of this and will probably be more jazzed than ever to continue working on it. If it doesn&amp;#8217;t, you won&amp;#8217;t have to spend any more time wondering &amp;#8220;what if&amp;#8221;. All in 2-3 days.&lt;/p&gt;
&lt;p&gt;(It&amp;#8217;s important to have realistic expectations of course. Are you going to be able to build the next Flickr in 48 hours? Or the next Facebook? Nope. But you sure can get a nice first iteration out there and working. Every application has to start somewhere, and if the first iteration of your idea isn&amp;#8217;t ugly and lacking important features, then there&amp;#8217;s a good chance it took you too long. Short iterations can pack a lot of result-fu ninja punch.)&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;#8217;ve rambled on for a bit and I&amp;#8217;m sorry. We&amp;#8217;ll do another Rumble, or something like it, later this year. For sure. But the reason I&amp;#8217;m writing is this: You don&amp;#8217;t have to wait.&lt;/p&gt;
&lt;p&gt;That is, you don&amp;#8217;t need an actual event to prove that this brand of ultra-mega &lt;span class="caps"&gt;CDD&lt;/span&gt; works.&lt;/p&gt;
&lt;p&gt;Take the last 3-4 days of this month, of next month, of whenever. If you&amp;#8217;re a freelancer, just tell clients you&amp;#8217;re unavailable during those days. Get 3 other people to do the same thing. Agree on an idea, flesh out the basics. And just do it, Nike-style.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m seriously thinking about doing just this, starting at the end of February, maybe at the end of each month. Anybody wanna be on my team?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Slacking</title>
   <link href="http://blog.zerosum.org/2008/1/30/slacking.html" />
   <published>2008-01-30T00:00:00-05:00</published>
   <updated>2008-01-30T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/1/30/slacking</id>
   <content type="html">&lt;p&gt;Like my pal bryanl over at &lt;a href="http://smartic.us/2008/1/30/missing-blog-posts"&gt;smartic.us&lt;/a&gt;, I too want to apologize for being a bad blogger lately. I&amp;#8217;ve just been stupid busy with both personal stuff and lotsa client work, which of course is both a blessing and a curse.&lt;/p&gt;
&lt;p&gt;In any case, my head is almost back above water and I hope to be back on track writing regular (and hopefully interesting) posts within the next week or two. I&amp;#8217;ve been working on some fun projects and I want to talk about it, really, but at the end of the day I&amp;#8217;m just tired and don&amp;#8217;t know where to begin. I&amp;#8217;ll figure it out.&lt;/p&gt;
&lt;p&gt;In the meantime, if you&amp;#8217;ve got free cycles and some cash in your wallet to burn, pick up a copy of Dave Berube&amp;#8217;s new book on &lt;a href="http://www.amazon.com/Practical-Reporting-Rails-David-Berube/dp/1590599330/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1201670634&amp;sr=8-1"&gt;Ruby Reporting&lt;/a&gt;, which was just published by Apress. I served as a technical reviewer on it, which was a really great experience. Even though Dave and I don&amp;#8217;t see eye to eye on absolutely everything (cue groans about a particular chapter dealing with MS Access integration), it&amp;#8217;s full of fun Ruby code and unique reporting tips, including examples that interop with Google AdWords, SugarCRM, and PayPal. Congrats man, nice work!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Railsconf Registration Open</title>
   <link href="http://blog.zerosum.org/2008/1/30/railsconf-08.html" />
   <published>2008-01-30T00:00:00-05:00</published>
   <updated>2008-01-30T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/1/30/railsconf-08</id>
   <content type="html">&lt;p&gt;Registration for &lt;a href="http://www.railsconf.com"&gt;Railsconf 2008&lt;/a&gt; opened earlier today. According to the site, there will be more advanced-level sessions this year, which is definitely a good thing. Last year was a fantastic experience, but it felt like I was constantly stumbling into sessions where the subject matter was a bit too noob-centric (thank goodness for the &lt;span class="caps"&gt;IRC&lt;/span&gt; peanut gallery).&lt;/p&gt;
&lt;p&gt;Of course, that said, as with all conferences, the discussions you get into in the hallways and after hours are usually more beneficial than any session you could ever attend anyway. But still, I&amp;#8217;m really hoping sessions are labeled with a suggested experience level this year.&lt;/p&gt;
&lt;p&gt;Am I going? Honestly don&amp;#8217;t know. I&amp;#8217;d like to. It&amp;#8217;s really an amazing thing to see 1500+ Ruby developers all descending upon one location at one time. That spectacle alone is probably worth the price of admission. Plus, the microbrews in Portland are top-notch. I&amp;#8217;m guessing it will sell out, so I better make up my mind sooner rather than later. How about you?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>NHRuby 2008</title>
   <link href="http://blog.zerosum.org/2008/1/14/nhruby-2008.html" />
   <published>2008-01-14T00:00:00-05:00</published>
   <updated>2008-01-14T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/1/14/nhruby-2008</id>
   <content type="html">&lt;p&gt;The Seacoast NH Ruby &lt;span class="caps"&gt;SIG&lt;/span&gt; (&lt;a href="http://wiki.nhruby.org"&gt;NHRuby&lt;/a&gt;) will hold it&amp;#8217;s first meeting of 2008 tomorrow, Tuesday January 15th in Portsmouth. I&amp;#8217;ll be talking about &lt;a href="http://www.openid.net"&gt;OpenID&lt;/a&gt; and &lt;a href="http://blog.zenlinux.com"&gt;Scott Garman&lt;/a&gt; will be doing an overview of some funky stuff he&amp;#8217;s doing with ActionMailer. Check out the &lt;a href="http://wiki.nhruby.org"&gt;Wiki&lt;/a&gt; for directions and other goodies, as usual. Hope to see you there!&lt;/p&gt;
&lt;p&gt;I also want to send a quick congratulatory note to Scott, who launched his Rails-based startup &lt;a href="http://www.campaignlever.com/"&gt;CampaignLever&lt;/a&gt; a few weeks ago. CampaignLever is a tool to help grassroots organizations build effective letter writing campaigns. Nice work man!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Storing YAML in YAML Fixtures</title>
   <link href="http://blog.zerosum.org/2008/1/10/yaml-in-yaml.html" />
   <published>2008-01-10T00:00:00-05:00</published>
   <updated>2008-01-10T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/1/10/yaml-in-yaml</id>
   <content type="html">&lt;p&gt;If you ever find yourself in a situation where you have an attribute value that needs to be serialized (stored as &lt;a href="http://yaml.org/"&gt;&lt;span class="caps"&gt;YAML&lt;/span&gt;&lt;/a&gt;) and used within a (&lt;span class="caps"&gt;YAML&lt;/span&gt;) fixture, you can do something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FancyWidget:
  id: 1
  name: FancyWidget
  serialized_hash: "&amp;lt;%= {:abc =&amp;gt; {:xyz =&amp;gt; 'foo'}}.to_yaml %&amp;gt;"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or, if you want to embed &lt;span class="caps"&gt;YAML&lt;/span&gt; directly you can do:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FancyWidget:
  id: 1
  name: FancyWidget
  serialized_hash: |
    ---
    :abc: 
      :xyz: foo&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is probably old hat to a lot of you, but I figured I&amp;#8217;d doc it here since the solution felt somewhat non-obvious at first. Rails stores serialized attributes in your database this way, so you might run into this if you&amp;#8217;re using ActiveRecord&amp;#8217;s &lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M001394"&gt;serialize&lt;/a&gt; method.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Coworking Jealousy</title>
   <link href="http://blog.zerosum.org/2008/1/6/coworking-jealousy.html" />
   <published>2008-01-06T00:00:00-05:00</published>
   <updated>2008-01-06T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2008/1/6/coworking-jealousy</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m calling it now: &lt;a href="http://en.wikipedia.org/wiki/Coworking"&gt;Coworking&lt;/a&gt; spaces are the new startup incubator. No, I&amp;#8217;m not talking about shared office space. No way. &lt;a href="http://blog.coworking.info/"&gt;It&amp;#8217;s different&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Coworking is a movement to create a community of cafe-like collaboration spaces for developers, writers and independents.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The whole concept feels very, very right to me. See, I don&amp;#8217;t really want coworkers, just like I don&amp;#8217;t really want a full-time ordinary run-of-the-mill 40 hour/week job; I&amp;#8217;d rather be sharing a space with 4-10 other self-motivated similarly-minded freelancers, who split their days between client work, personal startuppy ideas, and &lt;span class="caps"&gt;OSS&lt;/span&gt; projects. Especially ones that can hack some mean code, or who have a sick artistic bent.&lt;/p&gt;
&lt;p&gt;Of course, you need a critical mass to make something like this work, and people who can commit to participation. Those can be hairy obstacles. Coworking spaces usually develop in larger cities because, hey, they have the ecosystem to support it. The numbers are on their side. &lt;a href="http://citizenspace.us/"&gt;San&lt;/a&gt; &lt;a href="http://hatfactory.net/"&gt;Francisco&lt;/a&gt;, &lt;a href="http://www.affinitylab.com"&gt;Washington DC&lt;/a&gt;, &lt;a href="http://www.betahouse.org/"&gt;Boston&lt;/a&gt; and &lt;a href="http://officenomands.com"&gt;Seattle&lt;/a&gt; all have fairly well known coworking spaces. There are a number of entries at &lt;a href="http://coworking.pbwiki.com/"&gt;pbwiki&lt;/a&gt; for small cities, but for the most part, those links are just people who are &lt;strong&gt;interested&lt;/strong&gt; should something become available.&lt;/p&gt;
&lt;p&gt;Man, I&amp;#8217;m jealous. I want a coworking space in my city. Hrmm.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Reading List Update</title>
   <link href="http://blog.zerosum.org/2007/12/29/reading-list-update.html" />
   <published>2007-12-29T00:00:00-05:00</published>
   <updated>2007-12-29T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/12/29/reading-list-update</id>
   <content type="html">&lt;p&gt;So I updated this blog from &lt;a href="http://mephistoblog.com/download"&gt;Mephisto&lt;/a&gt; 0.7.3 to the latest &lt;a href="http://svn.techno-weenie.net/projects/mephisto/trunk"&gt;trunk&lt;/a&gt; yesterday and I&amp;#8217;m happy to report that the process was 100% painless. Edge has a number of nice nuggets missing from 0.7.x, which is over a year old at this point. In any case, thanks to Rick and the rest of the Mephisto team for the smooth upgrade path. I can&amp;#8217;t wait for 1.0, which I hear is rumored for a January release ;-).&lt;/p&gt;
&lt;p&gt;While I was in the blog tweaking mood I also decided to install the &lt;a href="http://hasno.info/2006/11/11/mephisto-plugins"&gt;mephisto_feedreader plugin&lt;/a&gt; and wired it up to display my &lt;a href="http://www.google.com/reader/shared/08653968643708044812"&gt;shared items&lt;/a&gt; from &lt;a href="http://www.google.com/reader/"&gt;Google Reader&lt;/a&gt;. This replaces the static &amp;#8220;reading list&amp;#8221; that was previously in the sidebar. I scan / read a good number of blogs, probably too many, and I often tag 2-3 things a day on average that I feel are useful / interesting / irreverent. Sharing is good and I have &lt;a href="http://arstechnica.com/news.ars/post/20071226-christmas-of-controversy-for-google-reader-team.html"&gt;nothing to hide&lt;/a&gt;. For great justice!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Holiday Gifts: Ruby 1.9</title>
   <link href="http://blog.zerosum.org/2007/12/26/holiday-gifts-ruby-1-9.html" />
   <published>2007-12-26T00:00:00-05:00</published>
   <updated>2007-12-26T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/12/26/holiday-gifts-ruby-1-9</id>
   <content type="html">&lt;p&gt;Happy holidays everybody. In case you haven&amp;#8217;t heard, &lt;a href="http://www.ruby-lang.org/en/news/2007/12/25/ruby-1-9-0-released/"&gt;Ruby 1.9&lt;/a&gt; was released yesterday. If you&amp;#8217;re not exhausted from overeating and traveling, I&amp;#8217;d encourage you to spend a few minutes taking it for a spin.&lt;/p&gt;
&lt;p&gt;Ruby now runs on top of &lt;span class="caps"&gt;YARV&lt;/span&gt;, and &lt;a href="http://antoniocangiano.com/2007/12/03/the-great-ruby-shootout/"&gt;these benchmarks&lt;/a&gt; indicate that there are some pretty impressive performance increases over 1.8.6. That said, 1.9 is a &lt;strong&gt;development release&lt;/strong&gt;; it&amp;#8217;s not currently intended for production use and don&amp;#8217;t expect Mongrel or Rails (or various other gems) to run on it just yet.&lt;/p&gt;
&lt;p&gt;For more information, Dave Thomas has written a nice, concise &lt;a href="http://pragdave.blogs.pragprog.com/pragdave/2007/12/ruby-19right-fo.html"&gt;list of pros and cons&lt;/a&gt; over on his blog, and Mauricio Fernandez has been maintaining a &lt;a href="http://eigenclass.org/hiki/Changes+in+Ruby+1.9"&gt;full list of changes&lt;/a&gt; found in 1.9. Enjoy!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>DataMapper 0.2.5 Released</title>
   <link href="http://blog.zerosum.org/2007/12/21/datamapper-0-2-5.html" />
   <published>2007-12-21T00:00:00-05:00</published>
   <updated>2007-12-21T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/12/21/datamapper-0-2-5</id>
   <content type="html">&lt;p&gt;Sam released &lt;a href="http://datamapper.rubyforge.org"&gt;DataMapper&lt;/a&gt; 0.2.5 on Wednesday. It includes a bunch of tasty bugfixes before our next leap to 0.3.&amp;#215;. Give it a try if you haven&amp;#8217;t, I think you&amp;#8217;ll like it. And if you don&amp;#8217;t, well, you&amp;#8217;re&amp;#8230; whatever.&lt;/p&gt;
&lt;p&gt;One of the changes that I&amp;#8217;m particularly fond of is proper method visibility for properties:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Person &amp;lt; DataMapper::Base
  property :ssn, :private =&amp;gt; true
  property :login, :protected =&amp;gt; true
  property :name
  property :address&lt;/code&gt;

&lt;code&gt;  has_many :dogs
  belongs_to :alien_overlord
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The private and protected options are really just shortcuts for (`:reader =&amp;gt; :public, :writer =&amp;gt; :private`) and (`:reader =&amp;gt; :public, :writer =&amp;gt; :protected`), respectively. In most cases you&amp;#8217;ll want your reader to be public, but if you want to apply the same visibility modifier to both reader and writer, there&amp;#8217;s an &amp;#8216;:accessor&amp;#8217; option too. The property visibility is respected for mass assignment, which is a nice natural way to do things imo, unlike the hacky &lt;a href="http://api.rubyonrails.com/classes/ActiveRecord/Base.html#M001390"&gt;attr_protected&lt;/a&gt; stuff in ActiveRecord, which never felt right to me.&lt;/p&gt;
&lt;p&gt;In any case, we&amp;#8217;ve also updated the &lt;a href="http://www.datamapper.org"&gt;Website&lt;/a&gt; and &lt;a href="http://www.datamapper.org/getting_started.html"&gt;Getting Started&lt;/a&gt; page, which was a little out of date. See those links for installation instructions and feel free to pop into the `#datamapper` channel on &lt;span class="caps"&gt;IRC&lt;/span&gt;, hit up the mailing list, or even leave blog comments here if you have any issues.&lt;/p&gt;
&lt;p&gt;Other important changes (see the changelog for a complete list):&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;`MyModel#[]` only accepts a primary key now, not an options hash (use first, all)&lt;/li&gt;
	&lt;li&gt;`database.get` (equivalent to AR&amp;#8217;s `find_by_id`) is approximately 25% faster than before!&lt;/li&gt;
	&lt;li&gt;Persistence module added (you no longer have to inherit from DM::Base, although I still prefer this approach)&lt;/li&gt;
	&lt;li&gt;You can now set indexes with `:index =&amp;gt; true` and `:index =&amp;gt; :unique`&lt;/li&gt;
	&lt;li&gt;Validatable gem now used for handling validations&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>To REST Or Not To REST...</title>
   <link href="http://blog.zerosum.org/2007/12/18/to-rest-or-not-to-rest.html" />
   <published>2007-12-18T00:00:00-05:00</published>
   <updated>2007-12-18T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/12/18/to-rest-or-not-to-rest</id>
   <content type="html">&lt;p&gt;Assaf Arkin is right, and I stand corrected. &lt;a href="http://www.amazon.com/gp/browse.html?node=342335011"&gt;SimpleDB&lt;/a&gt; ain&amp;#8217;t RESTful. Hell, it&amp;#8217;s not really even GETSful. But it sure sounds nice when they put it in the marketing literature. Sigh.&lt;/p&gt;
&lt;p&gt;From &lt;a href="http://www.subbu.org/weblogs/main/2007/12/a_restful_versi.html"&gt;Subbu&amp;#8217;s blog&lt;/a&gt;: &amp;#8220;The technology powering SimpleDB is definitely impressive [..] However, as a &lt;span class="caps"&gt;REST&lt;/span&gt; &lt;span class="caps"&gt;API&lt;/span&gt;, it is a disappointment. The &lt;span class="caps"&gt;API&lt;/span&gt; failed (a) to identify resources, and (b) to specify operations on resources in a RESTful way. It uses a single verb &lt;span class="caps"&gt;GET&lt;/span&gt; to create, delete, update, or get data from the store.&amp;#8221;&lt;/p&gt;
&lt;p&gt;In any case, Assaf whipped up &lt;a href="http://blog.labnotes.org/2007/12/17/dehorrible-restifying-simpledb/"&gt;DeHorrible&lt;/a&gt;, a Rails proxy that appropriately RESTifies (GETStifies) SimpleDB. lol.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m still psyched about the SimpleDB announcement, and looking forward to trying it out, but I really wish Amazon would clean up their supposedly RESTful APIs. Yes, I&amp;#8217;m looking at you, Flexible Payments.&lt;/p&gt;
&lt;p&gt;Is it really that hard?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Links for 12.17.07</title>
   <link href="http://blog.zerosum.org/2007/12/18/links-for-12-17-07.html" />
   <published>2007-12-18T00:00:00-05:00</published>
   <updated>2007-12-18T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/12/18/links-for-12-17-07</id>
   <content type="html">&lt;p&gt;Some git goodies, updates to both Rails and Merb, and other stuff this week. Here&amp;#8217;s the breakdown:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://evhead.com/2007/12/how-to-evaluate-new-product-idea.asp"&gt;Evan Williams&lt;/a&gt; writes about how to evaluate a new product idea&amp;lt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://evil.che.lu/2007/11/27/ann-giston-piston-lookalike-for-git"&gt;Giston&lt;/a&gt; &amp;#8212; a piston lookalike for git&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way"&gt;Gitosis&lt;/a&gt; &amp;#8212; host and manage a git repo, with access control, easily/safely&amp;#8230;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://blog.davidchelimsky.net/articles/2007/12/14/rspec-1-1"&gt;RSpec 1.1 is Released&lt;/a&gt; &amp;#8212; with support for Rails 2.0.1+ and the new RSpec story runner (!)&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://weblog.rubyonrails.com/2007/12/17/rails-2-0-2-some-new-defaults-and-a-few-fixes"&gt;Rails 2.0.2 is Released&lt;/a&gt; &amp;#8212; includes sqlite3 as the new default database and an important fix for RubyGems 0.9.5&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://brainspl.at/articles/2007/12/14/merb-0-4-2-released"&gt;Merb 0.4.2 is Released&lt;/a&gt; &amp;#8212; performance enhancements, etc.&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>SimpleDB is RESTful &amp; Schema-less?</title>
   <link href="http://blog.zerosum.org/2007/12/16/simpledb-restful-schema-less.html" />
   <published>2007-12-16T00:00:00-05:00</published>
   <updated>2007-12-16T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/12/16/simpledb-restful-schema-less</id>
   <content type="html">&lt;p&gt;So the big web service of the week announcement goes to Amazon, for their &lt;a href="http://www.amazon.com/gp/browse.html?node=342335011"&gt;&lt;span class="caps"&gt;AWS&lt;/span&gt; SimpleDB&lt;/a&gt; hosted service. This should place nicely with EC2, which is an interesting service except for the fact that persistent data across sessions is problematic (every time you boot an EC2 node it&amp;#8217;s a clean slate).&lt;/p&gt;
&lt;p&gt;So what is SimpleDB? It&amp;#8217;s:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Built in Erlang (wow, maybe Erlang is worth learning after all, right?)&lt;/li&gt;
	&lt;li&gt;&lt;strike&gt;RESTful&lt;/strike&gt;(see comments); &lt;span class="caps"&gt;API&lt;/span&gt; returns &lt;span class="caps"&gt;XML&lt;/span&gt;&lt;/li&gt;
	&lt;li&gt;Schema-less&lt;/li&gt;
	&lt;li&gt;Non-relational&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Wait, what? Schema-less? Non-relational? Yup. In case you haven&amp;#8217;t noticed, there&amp;#8217;s been a groundswell of interest in this area lately&amp;#8230; Perhaps most buzz-worthy is the &lt;a href="http://couchdb.org"&gt;CouchDB&lt;/a&gt; project, which also uses &lt;span class="caps"&gt;REST&lt;/span&gt; for inserts and queries, storing your data in schema-less databases which Amazon confusingly refers to as &amp;#8220;domains&amp;#8221; (see &lt;a href="http://www.automatthew.com/2007/12/amazon-simpledb-and-couchdb-compared.html"&gt;other differences&lt;/a&gt;). CouchDB is pretty neat, and all the cool kids seem to like it. &lt;a href="http://rddb.rubyforge.org/"&gt;&lt;span class="caps"&gt;RDDB&lt;/span&gt;&lt;/a&gt; has similar goals. And then there&amp;#8217;s &lt;a href="http://code.nytimes.com/projects/dbslayer"&gt;DBSlayer&lt;/a&gt;, which takes the approach of wrapping a &lt;span class="caps"&gt;REST&lt;/span&gt; &lt;span class="caps"&gt;API&lt;/span&gt; around traditional relational databases (MySQL, etc).&lt;/p&gt;
&lt;p&gt;So why the interest in moving away from traditional &lt;span class="caps"&gt;RDBMS&lt;/span&gt;, which have served us well for so many years? Simplicity. Ease of scaling. The emphasis on removing business logic from the database and keeping it in the application, where it belongs. At least, those are the arguments. I&amp;#8217;m no expert, but I&amp;#8217;m certainly interested. Assaf Arkin summarizes the argument much better than I can, and his article &lt;a href="http://blog.labnotes.org/2007/09/20/read-consistency-dumb-databases-smart-services/"&gt;Read Consistency: Dumb Databases, Smart Services&lt;/a&gt; should be required reading for anyone who&amp;#8217;s interested in the future of (dumb) databases on the web. Assaf also has a follow-up &lt;a href="http://blog.labnotes.org/2007/09/02/couchdb-thinking-beyond-the-rdbms/"&gt;article on the merits of CouchDB&lt;/a&gt;, specifically. There&amp;#8217;s a lot to think about here.&lt;/p&gt;
&lt;p&gt;Of course, another key value prop with the Amazon service is that it&amp;#8217;s &lt;strong&gt;hosted&lt;/strong&gt;. By Amazon. They claim it&amp;#8217;s fast and reliable (they should know a thing or two about that), and it looks to be relatively &lt;a href="http://www.amazon.com/gp/browse.html?node=34233501"&gt;inexpensive&lt;/a&gt;, when you consider that the alternative is clustering your own databases for the same kind of speed and reliability. It&amp;#8217;ll be interesting to see how this turns out and I&amp;#8217;m anxious to play around with it.&lt;/p&gt;
&lt;p&gt;All that said, there&amp;#8217;s no Ruby library wrapper for SimpleDB yet. However, as Chad Fowler notes, &lt;a href="http://www.chadfowler.com/2007/12/16/open-source-competition"&gt;there are already three different projects registered with RubyForge&lt;/a&gt;. None of them have checked in even a single file as of this writing, but you know that somebody out there is hard at work (hint hint), and I&amp;#8217;m sure you&amp;#8217;ll see it before too long. Alternatively, you can build one yourself.&lt;/p&gt;
&lt;p&gt;Me? I&amp;#8217;ve already got too much on my plate this week. And I still have to get that DataMapper cheat sheet done, too.&lt;/p&gt;
&lt;p&gt;/me apologizes again&lt;/p&gt;
&lt;p&gt;/me goes outside to shovel snow&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>NetBeans: Helpful Plugins</title>
   <link href="http://blog.zerosum.org/2007/12/13/netbeans-helpful-plugins.html" />
   <published>2007-12-13T00:00:00-05:00</published>
   <updated>2007-12-13T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/12/13/netbeans-helpful-plugins</id>
   <content type="html">&lt;p&gt;So, &lt;a href="http://download.netbeans.org/netbeans/6.0/final/"&gt;NetBeans 6.0 Final&lt;/a&gt; was released a few weeks ago. v6.0 is all about the Ruby love, right out of the box. If you haven&amp;#8217;t tried it, I implore you to give it a shot. Even if you&amp;#8217;re not a fan of traditional &amp;#8220;heavyweight&amp;#8221; IDEs, I think you&amp;#8217;ll be impressed with what they&amp;#8217;ve done. There&amp;#8217;s even a slimmed-down Ruby-only version. But sometimes, I must admit, I still miss the power and (relative) simplicity of vim.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m in the process of re-reading The Pragmatic Programmer, and was just pawing through the passage on &amp;#8220;power editing&amp;#8221;, in which Dave and Andy suggest that you &amp;#8220;choose [one] editor, know it thoroughly, and use it for all editing tasks&amp;#8221;. For me, that editor is most definitely vim. I&amp;#8217;ve used it for quite some time, it&amp;#8217;s familiar, I don&amp;#8217;t even have to think about the keybindings when I&amp;#8217;m working in vi, and I&amp;#8217;m spoilt by the easy text manipulations that just aren&amp;#8217;t possible with some fancy graphical editing tools. I use vim for practically everything text-related.&lt;/p&gt;
&lt;p&gt;Everything, that is, except writing Java and Ruby code (and a few random tasks that &lt;em&gt;have&lt;/em&gt; to be performed in a word processor, sadly). Yep, you read that right. I use vim for sysadmin tasks, hacking quick scripts, editing config files, and even taking notes, but lately I haven&amp;#8217;t been using it where I&amp;#8217;d probably see the single largest productivity boost from it.&lt;/p&gt;
&lt;p&gt;Since switching to NetBeans, my comfort level with having all the tools I need in one place has increased dramatically, including things such as easy access to a console, in-&lt;span class="caps"&gt;IDE&lt;/span&gt; debugging, test output, solid class introspection, integrated rdocs, and so on. But I also realize that I&amp;#8217;ve been doing myself a bit of a disservice when in &amp;#8220;heavy edit&amp;#8221; mode. Fortunately, that&amp;#8217;s easily fixed, as there&amp;#8217;s a vi plugin for NetBeans. &lt;span class="caps"&gt;YES&lt;/span&gt;. No idea why I didn&amp;#8217;t bother to search for something like this before.&lt;/p&gt;
&lt;p&gt;So in any case, if you&amp;#8217;re interested, you can retrieve the NetBeans plugin from the &lt;a href="http://jvi.sourceforge.net/"&gt;jVi homepage&lt;/a&gt;. The file named &lt;em&gt;nbvi-&lt;span class="caps"&gt;FOR&lt;/span&gt;-NB-RC1-1.1.2.&amp;#215;6&lt;/em&gt; is the one you want (as of this writing, anyway). Once you&amp;#8217;ve downloaded the package, you can install it in NetBeans by going to tools =&amp;gt; plugins. Choose the downloads tab, click &amp;#8216;add plugins&amp;#8217;, select the vim core and keybindings plugins, install them, and be happy. Thanks guys, this is so awesome.&lt;/p&gt;
&lt;p&gt;Oh and speaking of plugins, here are a few other helpful Ruby-related plugins for NetBeans that you may be interested in. Most of them are available through the plugins browser built into the &lt;span class="caps"&gt;IDE&lt;/span&gt;.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Rspec Support (nice!)&lt;/li&gt;
	&lt;li&gt;Ruby dark pastels color scheme (hrmm looks familiar&amp;#8230;)&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://mediacast.sun.com/details.jsp?id=3759"&gt;&lt;span class="caps"&gt;HAML&lt;/span&gt; and &lt;span class="caps"&gt;SASS&lt;/span&gt; plugin&lt;/a&gt; (if that&amp;#8217;s the way you roll)&lt;/li&gt;
	&lt;li&gt;Extra Source Code Hints&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Emerging Technologies Conference 2008</title>
   <link href="http://blog.zerosum.org/2007/12/9/emerging-technologies-cfp.html" />
   <published>2007-12-09T00:00:00-05:00</published>
   <updated>2007-12-09T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/12/9/emerging-technologies-cfp</id>
   <content type="html">&lt;p&gt;I really enjoy the technology conference ritual, make it a point to get to at least a few every year. I particularly enjoy the smaller regional conferences. Where else can you (a) get exposure to new technologies, (b) meet the smart hackers who created your favorite &lt;span class="caps"&gt;OSS&lt;/span&gt; tools, &amp;#169; get away from home for a long weekend, and (d) get schooled at &lt;a href="http://en.wikipedia.org/wiki/Mafia_(game)"&gt;werewolf&lt;/a&gt;, all at the same time?&lt;/p&gt;
&lt;p&gt;Alas, with winter upon us, it appears that the 2007 conference circuit is winding down. That means it&amp;#8217;s time to look forward to&amp;#8230; Why, the 2008 conference circuit, of course!&lt;/p&gt;
&lt;p&gt;The Third Annual &lt;a href="http://www.phillyemergingtech.com"&gt;Emerging Technologies for the Enterprise Conference&lt;/a&gt; has been announced; it will be held in Philadelphia, March 26-27th. Last year they had some great talks by high-profile Rubyists such as David Black, Geoff Grosenbach, and Amy Hoy. Rod Johnson, father of the Spring framework, also gave a talk last year.&lt;/p&gt;
&lt;p&gt;This year, Floyd Marinescu of InfoQ will be giving one of the keynotes. Obie Fernandez and Peter Armstrong (the author of &lt;a href="http://manning.com/armstrong/"&gt;Flexible Rails&lt;/a&gt;, which I&amp;#8217;m really looking forward to reading) have already been announced as Ruby community speakers.&lt;/p&gt;
&lt;p&gt;Got something worth talking about? Tracey asked me to note that there&amp;#8217;s an &lt;a href="http://www.phillyemergingtech.com/call.php"&gt;open call for presenters&lt;/a&gt;. The submission deadline is 1/7/08.&lt;/p&gt;
&lt;p&gt;Dates for &lt;a href="http://en.oreilly.com/rails2008/public/content/home"&gt;RailsConf&lt;/a&gt; (5/29-6/1), &lt;a href="http://on-ruby.blogspot.com/2007/10/mountainwest-rubyconf-2008-call-for.html"&gt;Mountain West RubyConf&lt;/a&gt; (3/28-3/29) and GoRuCo (4/26) have already been announced as well. Feel free to mention any other interesting events that I&amp;#8217;ve omitted in the comments!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rails 2.0 Released</title>
   <link href="http://blog.zerosum.org/2007/12/7/rails-2-0-released.html" />
   <published>2007-12-07T00:00:00-05:00</published>
   <updated>2007-12-07T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/12/7/rails-2-0-released</id>
   <content type="html">&lt;p&gt;It&amp;#8217;s official; &lt;a href="http://weblog.rubyonrails.com/2007/12/7/rails-2-0-it-s-done"&gt;Rails 2.0 was officially released this morning&lt;/a&gt;. Gem update rails to snag it. There&amp;#8217;s some great stuff in there, if you haven&amp;#8217;t been keeping track, including further augmentation to RESTful conventions, multiview, &lt;span class="caps"&gt;HTTP&lt;/span&gt; authentication, sexy migrations, and on and on and on.&lt;/p&gt;
&lt;p&gt;You can read all about it &lt;a href="http://weblog.rubyonrails.com/2007/12/7/rails-2-0-it-s-done"&gt;here&lt;/a&gt; and also make sure to check out the &lt;a href="http://ryandaigle.com/articles/2007/12/7/rails-2-0-final-released-summary-of-features"&gt;feature summaries&lt;/a&gt; that Ryan Daigle has put together as well as the series of &lt;a href="http://railscasts.com/"&gt;Railscasts&lt;/a&gt; Ryan Bates has been doing on the new features. Thanks for the hard work everyone.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Links For 12.05.07</title>
   <link href="http://blog.zerosum.org/2007/12/6/links-for-12-05-07.html" />
   <published>2007-12-06T00:00:00-05:00</published>
   <updated>2007-12-06T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/12/6/links-for-12-05-07</id>
   <content type="html">&lt;p&gt;Waiting at &lt;span class="caps"&gt;IAD&lt;/span&gt; for a connecting flight home (en route from Beijing). It&amp;#8217;s snowing. That means delays. I&amp;#8217;m tired. But at least I have some time to catch up on blog reading and link posting. Here&amp;#8217;s the rundown of goodies on my reading list atm:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://brainspl.at/articles/2007/12/02/a-quick-jaunt-through-merbs-framework-code"&gt;A Quick Jaunt Through Merb&amp;#8217;s Framework Code&lt;/a&gt; &amp;#8212; essential reading for anyone looking to get started with Merb.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.netbeans.org/"&gt;NetBeans 6.0 Final&lt;/a&gt; is officially released &amp;#8212; Best Ruby &lt;span class="caps"&gt;IDE&lt;/span&gt; on the planet imo, nice to see it finally finished and out there.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://on-ruby.blogspot.com/2007/12/netbeans-60-interview-with-tor-norbye.html"&gt;A Great Interview with Tor Norbye&lt;/a&gt; of the NetBeans team &amp;#8212; and the difficulties of doing proper Ruby type inference&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.techcrunch.com/2007/12/05/loic-le-meurs-ten-rules-for-startup-success/"&gt;Loic Le Meur&amp;#8217;s Ten Rules For Startup Success&lt;/a&gt; &amp;#8212; common sense of course, but good reading&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://toolmantim.com/article/2007/12/5/setting_up_a_new_rails_app_with_git"&gt;Setting Up a New Rails App with Git&lt;/a&gt; &amp;#8212; good getting started tutorial if you haven&amp;#8217;t yet switched over&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://blog.divoxx.com/"&gt;Rodrigo Kochenburger&lt;/a&gt; has a new blog &amp;#8212; he&amp;#8217;s a smart cat so make sure to add him to your feed reader&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Software Development 2.0 China</title>
   <link href="http://blog.zerosum.org/2007/11/29/sd2c.html" />
   <published>2007-11-29T00:00:00-05:00</published>
   <updated>2007-11-29T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/11/29/sd2c</id>
   <content type="html">&lt;p&gt;Today I&amp;#8217;m in Beijing, attending the &lt;a href="http://www.sd2china.cn/english/"&gt;&lt;span class="caps"&gt;CSDN&lt;/span&gt;-Dr. Dobb&amp;#8217;s Software Development 2.0&lt;/a&gt; conference. It&amp;#8217;s my first time in China and it&amp;#8217;s quite an honor to be here. I&amp;#8217;ll be giving a Ruby on Rails overview and code analysis talk as part of tomorrow afternoon&amp;#8217;s session. Looking forward to talks by Andrei Alexandrescu, Tenni Theurer, Dan Theurer, Jonathan Palley and of course DDJ&amp;#8217;s own &lt;a href="http://www.ddj.com/blog/portal/archives/editors_blog/"&gt;Jon Erickson&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Links For 11.24.07</title>
   <link href="http://blog.zerosum.org/2007/11/24/links-for-11-24-07.html" />
   <published>2007-11-24T00:00:00-05:00</published>
   <updated>2007-11-24T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/11/24/links-for-11-24-07</id>
   <content type="html">&lt;p&gt;&lt;img src="http://blog.zerosum.org/assets/2007/11/24/built_on_nb_big.gif" style="float: right;"/&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://ennerchi.com/projects/jrails"&gt;JRails&lt;/a&gt; &amp;#8211; Drop-in JQuery replacement for Rails prototype/script.aculo.us helpers.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://download.netbeans.org/netbeans/6.0/rc2/"&gt;NetBeans 6.0 RC2&lt;/a&gt; &amp;#8211; Available for download.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.gemtacular.com"&gt;Gemtacular&lt;/a&gt; &amp;#8211; Rate and Review Ruby Gems.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://debu.gs/live-console"&gt;LiveConsole&lt;/a&gt; &amp;#8211; IRb over &lt;span class="caps"&gt;TCP&lt;/span&gt; remote console. Cool idea.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.techcrunch.com/2007/11/20/the-google-set-top-box-think-android-for-tv/"&gt;Google TV?&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.pivotalblabs.com/articles/2007/11/17/rake-query_trace"&gt;Rake tasks for QueryTrace&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://weblog.rubyonrails.org/2007/11/24/ruby-on-rails-1-2-6-security-and-maintenance-release"&gt;Rails 1.2.6&lt;/a&gt; &amp;#8211; Includes an important security fix. gem update rails -y&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Ruby Method Visibility</title>
   <link href="http://blog.zerosum.org/2007/11/22/ruby-method-visibility.html" />
   <published>2007-11-22T00:00:00-05:00</published>
   <updated>2007-11-22T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/11/22/ruby-method-visibility</id>
   <content type="html">&lt;p&gt;In Java (and most OO languages), declaring a method as &lt;strong&gt;private&lt;/strong&gt; means that the method can only be accessed within the context of the defining class. Similarly, &lt;strong&gt;protected&lt;/strong&gt; means that the method can only be accessed from that class or any of its subclasses.&lt;/p&gt;
&lt;p&gt;In Ruby, things are a bit different. Both private and protected methods can be called by &lt;em&gt;any instance&lt;/em&gt; of the defining class and its subclasses. Inheritance plays absolutely no role in determining the visibility of a method. The difference instead is that private methods can never be called with an explicit receiver, even if the receiver is &lt;code&gt;self&lt;/code&gt;. This means that it&amp;#8217;s not possible to access another object&amp;#8217;s private methods, even if the object is of the same type as the caller. A private method &lt;em&gt;must&lt;/em&gt; be called from within the calling object.&lt;/p&gt;
&lt;p&gt;Consider the following example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Person
  def public_method
    "public"
  end&lt;/code&gt;

&lt;code&gt;  protected
  def protected_method
    "protected"
  end&lt;/code&gt;

&lt;code&gt;  private
  def private_method
    "private"
  end
end&lt;/code&gt;

&lt;code&gt;class SalesPerson &amp;lt; Person
  def check_protected_method_explicit_receiver
    "#{self.protected_method} method OK with explicit receiver"
  rescue
    "failure accessing protected method with explicit receiver"
  end&lt;/code&gt;

&lt;code&gt;  def check_protected_method_implicit_receiver
    "#{protected_method} method OK with implicit receiver"
  rescue
    "failure accessing protected method with implicit receiver"
  end&lt;/code&gt;

&lt;code&gt;  def check_private_method_explicit_receiver
    "#{self.private_method} method OK with explicit receiver"
  rescue
    "failure accessing private method with explicit receiver"
  end&lt;/code&gt;

&lt;code&gt;  def check_private_method_implicit_receiver
    "#{private_method} method OK with implicit receiver"
  rescue
    "failure accessing private method with implicit receiver"
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The public method can of course be accessed from anywhere (in this case, outside the class with an explicit receiver) and both private and protected methods of &lt;code&gt;Person&lt;/code&gt; will obviously raise a &lt;code&gt;NoMethodError&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Person.new.public_method
=&amp;gt; "public"
Person.new.private_method
=&amp;gt; NoMethodError: private method `private_method' called for #&amp;lt;Person:0x6ec698&amp;gt;
Person.new.protected_method
=&amp;gt; NoMethodError: protected method `protected_method' called for #&amp;lt;Person:0x6ea5c8&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So the protected method cannot be accessed outside of the class or it&amp;#8217;s subclass, but from within the subclass, using it with either an implicit or explicit receiver works fine:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SalesPerson.new.check_protected_method_explicit_receiver
=&amp;gt; "protected method OK with explicit receiver"
SalesPerson.new.check_protected_method_implicit_receiver
=&amp;gt; "protected method OK with implicit receiver"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The private method can also be called from the subclass, but note how it only works with an implicit receiver:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SalesPerson.new.check_private_method_explicit_receiver
=&amp;gt; "failure accessing private method with explicit receiver"
SalesPerson.new.check_private_method_implicit_receiver
=&amp;gt; "private method OK with implicit receiver"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This also means you can do stuff like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Person
  def ==(other)
    protected_method == other.protected_method
  end
end&lt;/code&gt;

&lt;code&gt;x = SalesPerson.new
y = Person.new
x == y
=&amp;gt; true&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#8217;re accessing the &lt;code&gt;protected_method&lt;/code&gt; of another class instance that shares our type here, specifying an explicit receiver. If you were to try to use &lt;code&gt;private_method&lt;/code&gt; instead, a &lt;code&gt;NoMethodError&lt;/code&gt; would be raised. You could also just call &lt;code&gt;other.send("private_method")&lt;/code&gt; if you really wanted to, violating our encapsulation and angering the gods of object orientation. This is only a &amp;#8220;little sin&amp;#8221; though, and can be permissible if the situation calls for it (like, cough cough, my latest commit to DataMapper).&lt;/p&gt;
&lt;p&gt;In summary, method visibility and access control can be a bit confusing at first, especially if you&amp;#8217;re coming over to Ruby from some other OO language. If you&amp;#8217;re still confused, there&amp;#8217;s more information available &lt;a href="http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_classes.html"&gt;here&lt;/a&gt; and &lt;a href="http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby"&gt;here&lt;/a&gt;. Do yourself a favor and make sure you understand, cuz it&amp;#8217;s important stuff!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Steinbeck on Ruby?</title>
   <link href="http://blog.zerosum.org/2007/11/21/steinbeck-on-ruby.html" />
   <published>2007-11-21T00:00:00-05:00</published>
   <updated>2007-11-21T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/11/21/steinbeck-on-ruby</id>
   <content type="html">&lt;h4&gt;&amp;#8220;Syntax, my lad. It has been restored to the highest place in the republic.&amp;#8221;&lt;/h4&gt;
&lt;div align="right"&gt;&lt;strong&gt;&amp;#8212; John Steinbeck&lt;/strong&gt;&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Book Review: Practical Ruby Gems</title>
   <link href="http://blog.zerosum.org/2007/11/17/book-review-practical-ruby-gems.html" />
   <published>2007-11-17T00:00:00-05:00</published>
   <updated>2007-11-17T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/11/17/book-review-practical-ruby-gems</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been meaning to start posting book reviews for some time now. I don&amp;#8217;t really have a good excuse as to why I haven&amp;#8217;t, so I&amp;#8217;ll spare you the overly verbose excuses and get right to the good stuff.&lt;/p&gt;
&lt;p&gt;The first book in my stack is David Berube&amp;#8217;s &lt;a href="http://apress.com/book/view/1590598113"&gt;Practical Ruby Gems&lt;/a&gt;. Before diving into it I should note that Dave is a friend of mine and that I&amp;#8217;m currently working on a book with him for Apress. My opinions here are, of course, my own.&lt;/p&gt;
&lt;p&gt;Practical Ruby Gems is a survey book, covering a number of 3rd party Ruby libraries as well as general usage of the Gems system itself. Although it&amp;#8217;s a bit short on details in some places, the breadth over depth approach is really quite useful in that the book will doubtlessly introduce you to some libraries that you weren&amp;#8217;t aware of before. This is particularly true if the majority of your Ruby experience has been within the context of Rails. A number of the chapters do make use of Rails (hey, it is a Gem after all), a few use the Camping web framework, but the majority of the examples are constructed as simple command line utilities.&lt;/p&gt;
&lt;p&gt;The more popular Gems, such as hrpicot and rmagick are of course covered here, but the real (ahem) gems are the lesser known libraries such as multi, memoize, runt and cmdparse. Dave&amp;#8217;s examples cover a wide variety of topics and use each Gem in an interesting way, going beyond the rdocs to show you how to combine and use these libraries in real applications. Using Fxruby and the YahooFinance Gem to create a graphical stock ticker is a good example of this. Another example is an &lt;span class="caps"&gt;RSS&lt;/span&gt; news archiving service built using ActiveRecord and FeedTools. Both practical and well-dissected in the text, this sort of thing is sure to help new Ruby developers grasp the concepts for re-use in their own developments.&lt;/p&gt;
&lt;p&gt;The chapters on creating and distributing gems (with Rubyforge, gem_server, etc) are short and to the point. The one omission, from my point of view, is that Dr Nic&amp;#8217;s &lt;a href="http://newgem.rubyforge.org/"&gt;New Gem Generator&lt;/a&gt; isn&amp;#8217;t mentioned as a resource for bootstrapping gem structure. This is an invaluable tool for creating new gems.&lt;/p&gt;
&lt;p&gt;In any case, if you&amp;#8217;re looking to broaden your Ruby tool belt, Practical Ruby Gems is sure to give you exposure to a few new tools. It would be a particularly good &amp;#8216;bridge book&amp;#8217; for Rails developers who are looking to explore the world of Ruby possibilities outside of the web framework.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Turn On Your Buzzword Filter</title>
   <link href="http://blog.zerosum.org/2007/11/13/turn-on-your-buzzword-filter.html" />
   <published>2007-11-13T00:00:00-05:00</published>
   <updated>2007-11-13T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/11/13/turn-on-your-buzzword-filter</id>
   <content type="html">&lt;p&gt;BigLove [12:37am]: my eyes crossed from all the buzzwords zapnap&lt;br/&gt;
zapnap [12:38am]: turn on your buzzword filter. &lt;span class="caps"&gt;OMFG&lt;/span&gt; &lt;span class="caps"&gt;WHERE&lt;/span&gt; &lt;span class="caps"&gt;DID&lt;/span&gt; T EH &lt;span class="caps"&gt;INTERNETS&lt;/span&gt; GO?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Digital Comics, Unlimited</title>
   <link href="http://blog.zerosum.org/2007/11/13/digital-comics-unlimited.html" />
   <published>2007-11-13T00:00:00-05:00</published>
   <updated>2007-11-13T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/11/13/digital-comics-unlimited</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m not ashamed to admit that I&amp;#8217;m a bit of a comic book geek.&lt;/p&gt;
&lt;p&gt;When I was a kid, I was a hardcore fanboy who spent pretty nearly all his paper route money on weekly trips to the local comic shop in Dover. I have no apology for that. As a technology geek also, I&amp;#8217;ve built a social comic book pull list organizer that &lt;a href="http://collectic.us"&gt;has yet to officially launch&lt;/a&gt; (we&amp;#8217;re looking for someone who&amp;#8217;s excited about comics and community building, no techie skills required, email me if you&amp;#8217;re interested!) and I&amp;#8217;ve done a little ancillary plugin work for the geeky folks over at &lt;a href="http://heavyink.com"&gt;Heavy Ink&lt;/a&gt; too.&lt;/p&gt;
&lt;p&gt;These days I buy mostly graphic novels, but I&amp;#8217;ve always loved the feel of a floppy, and back when I used to buy titles monthly, there was just something unspeakably awesome about &amp;#8216;new comic book day&amp;#8217; and the excitement of pouring through the stacks in a local shop looking for that one key back issue&amp;#8230;&lt;/p&gt;
&lt;p&gt;Like most fans, I have mixed feelings about the digitization of comics. On one hand, I&amp;#8217;d probably read a lot more of them if they were available (ahem, legally of course) through a cheap, easy to use digital distribution service like iTunes. On the other hand, I&amp;#8217;m sort of glad this hasn&amp;#8217;t happened, because it would kill a lot of the allure of it for me if the comics on paper were to become a thing of the past.&lt;/p&gt;
&lt;p&gt;I imagine I&amp;#8217;m not the only one who was both excited and, at the same time, just a little tiny bit bummed about the &lt;a href="http://www.newsarama.com/marvelnew/Online/MarvelOnlinea.html"&gt;announcement&lt;/a&gt; of &lt;a href="http://marvel.com/digitalcomics"&gt;Marvel Comics Unlimited&lt;/a&gt; yesterday (&lt;em&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;: as of right now the site appears to be down for maintenance, coming soon&lt;/em&gt;). The basic premise is that Marvel will offer an online archive of over 2500 back issues online in high-resolution format, starting at about $5/mo. They&amp;#8217;re also making a free sampler of 250 titles available to wet your appetites.&lt;/p&gt;
&lt;p&gt;Marvel&amp;#8217;s hedging their bets a little though, which is smart. New issues won&amp;#8217;t appear on the Marvel Unlimited site until six months after their initial print publication. This is great for those of us who read graphic novels, and aren&amp;#8217;t used to picking up books every week anyway, and it keeps the floppies in circulation. After a bit of consternation, I&amp;#8217;ve decided that it&amp;#8217;s pretty much a win/win. Of course, as it always is on the web, the user experience will determine the ultimate success or failure of the venture. The flash-based digital comics I&amp;#8217;ve seen from Marvel up to this point haven&amp;#8217;t exactly been the most pleasant things to read, so here&amp;#8217;s to hoping this is an entirely new interface to the library.&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;#8217;m looking forward to reading more about this, both as a comic book enthusiast and as a technologist. Welcome to the 21st century, comic fans. For better or for worse.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s about time, I guess!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>OS X Leopard Upgrade Notes</title>
   <link href="http://blog.zerosum.org/2007/11/11/os-x-leopard-upgrade-notes.html" />
   <published>2007-11-11T00:00:00-05:00</published>
   <updated>2007-11-11T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/11/11/os-x-leopard-upgrade-notes</id>
   <content type="html">&lt;p&gt;Starting this blog entry to document any possible gotchas I experience on my upgrade to OS X 10.5. So far everything has been relatively clean. My only problem as of this writing has been with &lt;span class="caps"&gt;SSH&lt;/span&gt; and &lt;a href="http://www.macports.org/"&gt;MacPorts&lt;/a&gt;. I have &lt;span class="caps"&gt;SSH&lt;/span&gt; installed via MacPorts and I noticed when doing any SVN+SSH operations, I was getting the following error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;percent_expand: NULL replacement
svn: Connection closed unexpectedly&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hmm, looks like Leopard is expanding some &lt;span class="caps"&gt;SSH&lt;/span&gt; environmental variable to &lt;span class="caps"&gt;NULL&lt;/span&gt;. An easy fix is to add the following line to your &lt;em&gt;~/.ssh/config&lt;/em&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IdentityFile ~/.ssh/id_rsa&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This overrides the default search for your private key, and therefore you don&amp;#8217;t get the percent_expand error. If anyone has more information about this particular issue, please let me know. Thanks!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Links For 11.10.07</title>
   <link href="http://blog.zerosum.org/2007/11/10/links-for-11-10-07.html" />
   <published>2007-11-10T00:00:00-05:00</published>
   <updated>2007-11-10T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/11/10/links-for-11-10-07</id>
   <content type="html">&lt;p&gt;&lt;img src="http://www.freebsd.org/gifs/power.jpg" style="float: right;"/&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://people.freebsd.org/~kris/scaling/7.0%20Preview.pdf"&gt;FreeBSD 7.0&lt;/a&gt; is  is going to own scaling. Srsly. RC1 should be available this week.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://weblog.rubyonrails.org/2007/11/9/rails-2-0-release-candidate-1"&gt;Rails 2.0 RC1&lt;/a&gt; is here. Have you fixed those deprecation warnings in 1.2.5 yet?&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://heroku.com/"&gt;Heroku&lt;/a&gt; is coming next week. Holy crap those screencasts are cool. So the future of building and hosting webapps looks a lot like Seaside, eh?&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://gilesbowkett.blogspot.com/2007/11/heroku.html"&gt;More Heroku coverage&lt;/a&gt; and commentary by Giles Bowkett.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://hassox.blogspot.com/2007/11/great-merb-speedup.html"&gt;The Great Merb Speedup&lt;/a&gt;. Keep your eyes peeled for 0.4.1, things in this camp keep getting better and better.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://radar.oreilly.com/archives/2007/11/opensocial_social_mashups.html"&gt;Interesting critique of OpenSocial&lt;/a&gt; from Tim O&amp;#8217;Reilly.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://opensocialapis.blogspot.com/"&gt;Google&amp;#8217;s OpenSocial &lt;span class="caps"&gt;API&lt;/span&gt; Blog&lt;/a&gt;, because it&amp;#8217;s the new hotness.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://blog.nbwd.co.uk/2007/11/7/opensocial-with-ruby-on-rails"&gt;Using OpenSocial with Ruby on Rails&lt;/a&gt;, because hey, you&amp;#8217;re curious, right?&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>NH Ruby Next Monday Night</title>
   <link href="http://blog.zerosum.org/2007/11/9/nh-ruby-next-monday.html" />
   <published>2007-11-09T00:00:00-05:00</published>
   <updated>2007-11-09T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/11/9/nh-ruby-next-monday</id>
   <content type="html">&lt;p&gt;As Scott notes over on &lt;a href="http://blog.zenlinux.com/?p=125"&gt;his blog&lt;/a&gt;, this month&amp;#8217;s &lt;a href="http://wiki.nhruby.org"&gt;NH Ruby&lt;/a&gt; meeting will be off by a week and a day this time around, due to holiday stuff. Instead of the third Tuesday of the month, it&amp;#8217;ll be the second &lt;em&gt;Monday&lt;/em&gt;. Yessir, that&amp;#8217;s this coming Monday.&lt;/p&gt;
&lt;p&gt;My good friend &lt;a href="http://www.berubeconsulting.com"&gt;Dave Berube&lt;/a&gt; will be the main speaker, and he&amp;#8217;ll be discussing reporting techniques with Ruby and Rails. Dave is putting the finishing touches on a &lt;a href="http://www.amazon.com/Practical-Reporting-Rails-David-Berube/dp/1590599330/ref=sr_1_1/102-5578455-2298507?ie=UTF8&amp;s=books&amp;qid=1194585918&amp;sr=8-1"&gt;new book&lt;/a&gt; on the subject, so he knows of that which he speaks. It&amp;#8217;s sure to be a good conversation and if you&amp;#8217;re in the area, you should definitely check us out.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Flexible Payments With Rails &amp; REST</title>
   <link href="http://blog.zerosum.org/2007/11/9/flexible-payments-with-rails-rest.html" />
   <published>2007-11-09T00:00:00-05:00</published>
   <updated>2007-11-09T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/11/9/flexible-payments-with-rails-rest</id>
   <content type="html">&lt;p&gt;Anyone who&amp;#8217;s been playing around with the original Rails version of the &lt;a href="http://www.amazon.com/b?ie=UTF8&amp;node=342430011"&gt;Amazon Flexible Payments Service&lt;/a&gt; sample application has probably spent a fair amount of time swearing and complaining about how incredibly un-idiomatic and ugly it is. I know I have. It&amp;#8217;s not that we don&amp;#8217;t appreciate Amazon wanting to play ball with us, it&amp;#8217;s just that it&amp;#8217;s&amp;#8230; well&amp;#8230; it&amp;#8217;s damn ugly.&lt;/p&gt;
&lt;p&gt;But wait, a few weeks ago, a new &lt;span class="caps"&gt;REST&lt;/span&gt;-based Rails sample app was posted. This time around it&amp;#8217;s a far more basic &amp;#8220;hello world&amp;#8221;-ish app, but it&amp;#8217;s much more idiomatic and clean, a far better starting place for anyone who wants to learn how to make pay calls with &lt;span class="caps"&gt;FPS&lt;/span&gt; using Ruby and Rails. It&amp;#8217;s also thankfully devoid of soap4r dependencies.&lt;/p&gt;
&lt;p&gt;Just thought I&amp;#8217;d note that, in case you&amp;#8217;re working with &lt;span class="caps"&gt;FPS&lt;/span&gt; and haven&amp;#8217;t stumbled upon it yet.&lt;/p&gt;
&lt;p&gt;In related news, there&amp;#8217;s a RubyForge project for a library called &lt;a href="http://rubyforge.org/projects/remit/"&gt;Remit&lt;/a&gt;, which purports to be a proper Ruby &lt;span class="caps"&gt;API&lt;/span&gt; wrapper for &lt;span class="caps"&gt;FPS&lt;/span&gt;. &lt;a href="http://blog.tylerhunt.com"&gt;Tyler Hunt&lt;/a&gt; is the developer who&amp;#8217;s registered the project and is working on it. With no updates since &lt;a href="http://blog.tylerhunt.com/2007/9/6/heavyweight-wrapper-apis"&gt;early September&lt;/a&gt; though, and  no files released, I wonder if the project hasn&amp;#8217;t maybe been aborted? Tyler, if you&amp;#8217;re out there, give a shout and let us know if you need a hand.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Merbivore!</title>
   <link href="http://blog.zerosum.org/2007/11/7/merbivore.html" />
   <published>2007-11-07T00:00:00-05:00</published>
   <updated>2007-11-07T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/11/7/merbivore</id>
   <content type="html">&lt;p&gt;&lt;a href="http://brainspl.at/articles/2007/11/07/merb-0-4-0-released-with-new-site-merbivore-com"&gt;Merb 0.4&lt;/a&gt; was released earlier today, and the men of Montreal were thus elated. For those that are unfamiliar with it, Merb is a Ruby &lt;span class="caps"&gt;MVC&lt;/span&gt; web framework not unlike Rails, but focused more on speed and minimalism. It&amp;#8217;s a lot like a thread-safe closer-to-the-metal reimplementation of ActionPack. This also means it&amp;#8217;s &lt;span class="caps"&gt;ORM&lt;/span&gt; agnostic (big, big win) and JavaScript library agnostic. Plugins are just gems (dependency management ftw), and it&amp;#8217;s fast and easily extensible. If you haven&amp;#8217;t used it before, now&amp;#8217;s the time to get started!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gem install merb -y&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The release announcement on &lt;a href="http://brainspl.at/articles/2007/11/07/merb-0-4-0-released-with-new-site-merbivore-com"&gt;Ezra&amp;#8217;s blog&lt;/a&gt; has a nice summary to some of the more significant improvements, and links to more in-depth coverage. Along with the gem update comes a brand spankin new website, &lt;a href="http://www.merbivore.com"&gt;merbivore.com&lt;/a&gt; to boot. Congrats guys, on what looks like a huge leap forward. I can&amp;#8217;t wait to dig in tomorrow.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Drop A PID For Monit</title>
   <link href="http://blog.zerosum.org/2007/11/6/drop-a-pid-for-monit.html" />
   <published>2007-11-06T00:00:00-05:00</published>
   <updated>2007-11-06T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/11/6/drop-a-pid-for-monit</id>
   <content type="html">&lt;p&gt;If you ever need to drop a pid from a Ruby process it&amp;#8217;s dead simple:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;File.open('myapp.pid', 'w') { |f| f.write(Process.pid) }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can use &lt;a href="http://www.tildeslash.com/monit/"&gt;Monit&lt;/a&gt; to keep Sinatra alive, for instance ;-). Monit is great for monitoring UN*X processes and keeping them running under ideal conditions, and that means &lt;a href="http://www.igvita.com/blog/2006/11/07/monit-makes-mongrel-play-nice/"&gt;it&amp;#8217;s great for Mongrel, and anything that runs through Mongrel&lt;/a&gt;. Monit can even check the memory consumption of your application and restart it if it seems to be leaking. Not that &lt;em&gt;&lt;strong&gt;that&lt;/strong&gt;&lt;/em&gt; ever happens, of course.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>I Am Not A Freeloader</title>
   <link href="http://blog.zerosum.org/2007/11/6/are-you-a-freeloader.html" />
   <published>2007-11-06T00:00:00-05:00</published>
   <updated>2007-11-06T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/11/6/are-you-a-freeloader</id>
   <content type="html">&lt;p&gt;So have you heard the new &lt;a href="http://www.inrainbows.com"&gt;Radiohead&lt;/a&gt; album yet? What did you think? And more importantly, what did you pay for it? ComScore estimates that 2 out of 5 of you did. They released a study today suggesting that, during the month of October, &lt;a href="http://www.comscore.com/press/release.asp?press=1883"&gt;40% of visitors were willing to pay an average of $6.00 for the digital downloads&lt;/a&gt;. Click that link for the full details. It&amp;#8217;s also interesting to note that US consumers were will to pay more, on average, than the rest of the world.&lt;/p&gt;
&lt;p&gt;The &lt;a href="http://mashable.com/2007/11/05/radiohead-music-industry-machine/"&gt;press&lt;/a&gt; is having a &lt;a href="http://thelede.blogs.nytimes.com/2007/11/05/checking-in-on-radioheads-experiment/?hp"&gt;field day&lt;/a&gt; with &lt;a href="http://www.news.com/8301-10784_3-9811013-7.html"&gt;this&lt;/a&gt;, and opinions are mixed. The &amp;#8216;glass is half empty&amp;#8217; point of view seems to be that, holy crap, there are a lot of freeloaders on the &amp;#8217;net.&lt;/p&gt;
&lt;p&gt;No kidding, really?&lt;/p&gt;
&lt;p&gt;On the other hand, the &amp;#8216;glass is half full&amp;#8217; folks point out that, hey, people are actually willing to pay for stuff, and that music on the &amp;#8217;net still has a perceived value after all.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m siding with the latter camp. Official sales figures won&amp;#8217;t be released until after the holidays, but shit, I think these initial estimates are fantastic. Moreover, I think they show tremendous potential for non-compulsory tipping for digital goods in the public space. Software and media piracy is only a problem because of how we perceive and hope to profit from selling media on the web. Labels don&amp;#8217;t need a new type of &lt;span class="caps"&gt;DRM&lt;/span&gt;, they need a new approach to what they&amp;#8217;re selling. It&amp;#8217;s information, and once that information is out there, it&amp;#8217;s free, regardless of how much you perceive it&amp;#8217;s worth to be. Magazine publishers figured this out a while back, and make their money through online advertising.&lt;/p&gt;
&lt;p&gt;What Radiohead has done is adapt, and prove that, at least to some extent, a donation-driven model can work here. Of course, public radio beat them to the punch by at least 50 years, and they&amp;#8217;re not the first band to sell music online, but it certainly signals a big win for those of us who believe that all web users aren&amp;#8217;t freeloading scum. Even if the average user &lt;em&gt;is&lt;/em&gt; a freeloader, the point is that the band can make &lt;em&gt;enough&lt;/em&gt; from their efforts such that producing art for public consumption is profitable.&lt;/p&gt;
&lt;p&gt;Anyway, the average worldwide price for all downloads, including freeloaders, was $2.26. I&amp;#8217;d love to know what the bands&amp;#8217; actual per-album net was on their previous album, 2003&amp;#8217;s Hail To The Thief. I&amp;#8217;d be shocked if it was much higher than, say, $6.00 (&lt;em&gt;update:&lt;/em&gt; &lt;a href="http://www.news.com/8301-10784_3-9811013-7.html"&gt;this article&lt;/a&gt; estimates that it was probably between $3 and $5 &lt;span class="caps"&gt;USD&lt;/span&gt;). Personally I paid about $7 &lt;span class="caps"&gt;USD&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Oh, and the album is pretty good too.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Clone Pastie in 15 Minutes with Sinatra &amp; DataMapper</title>
   <link href="http://blog.zerosum.org/2007/11/5/build-a-simple-pastie-clone-with-sinatra-datamapper-in-15-minutes.html" />
   <published>2007-11-05T00:00:00-05:00</published>
   <updated>2007-11-05T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/11/5/build-a-simple-pastie-clone-with-sinatra-datamapper-in-15-minutes</id>
   <content type="html">&lt;p&gt;Hey there, put on your tutorial hat. Today we&amp;#8217;re going to learn how to write a dirt simple pastie clone using Sinatra and Datamapper. For those of you unfamiliar with pastie systems, they&amp;#8217;re commonly used in &lt;span class="caps"&gt;IRC&lt;/span&gt; to paste bits of code to a globally-visible place outside of the channel. So you copy some code from your &lt;span class="caps"&gt;IDE&lt;/span&gt;, paste it into a web page, submit it, and the Pastie system fancies it up with some syntax highlighting or whatnot. You can then copy the resultant &lt;span class="caps"&gt;URL&lt;/span&gt; and paste it back into the channel so other people can view it.&lt;/p&gt;
&lt;p&gt;Examples of this type of service include &lt;a href="http://pastie.caboo.se"&gt;pastie.caboo.se&lt;/a&gt; and &lt;a href="http://www.rafb.net/paste/"&gt;Nopaste&lt;/a&gt; @ rafb.net. Those sites do a lot of extra cool stuff, like allow you to select the language for different syntax highlighting, select themes for viewing, and so on. But the core concept itself isn&amp;#8217;t a terribly complex one, and our example is going to be about as barebones as they come. The interesting thing isn&amp;#8217;t the application we&amp;#8217;re going to build here so much as it is the tools we&amp;#8217;ll use. That is, we&amp;#8217;ll be using the pastie example to introduce you to two cool new pieces of Ruby tech: Sinatra, a new web micro-framework, and the DataMapper &lt;span class="caps"&gt;ORM&lt;/span&gt; package.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://sinatra.rubyforge.org/"&gt;Sinatra&lt;/a&gt;, on the surface, is a lot like &lt;a href="http://redhanded.hobix.com/bits/campingAMicroframework.html"&gt;Camping&lt;/a&gt;, another Ruby web all-in-one-file micro-framework. Camping hasn&amp;#8217;t seen any active development in quite some time though, and the syntax can be a bit strange for new users. Sinatra is much more straight-forward and accessible. It&amp;#8217;s really a kind of domain-specific language for writing simple web applications, used to define RESTful actions and how they should be handled. This makes it perfect for lightweight mini-apps. It&amp;#8217;s also completely &lt;span class="caps"&gt;ORM&lt;/span&gt;-agnostic, instead of being married to ActiveRecord like both Rails and Camping are. For more information, &lt;a href="http://www.xnot.org/sinatra/beginning.html"&gt;check out the &amp;#8216;official&amp;#8217; tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://datamapper.org"&gt;DataMapper&lt;/a&gt; is the new &lt;span class="caps"&gt;ORM&lt;/span&gt; package on the block, and an alternative to ActiveRecord (and Og and Sequel and so on). It just moved into town but it&amp;#8217;s already sitting at the cool kid lunch table. Whereas AR implements the ActiveRecord Pattern, DataMapper (surprise!) implements the DataMapper pattern. There are a number of reasons why I prefer this approach, but that&amp;#8217;s probably fodder for an entirely separate blog post, so I won&amp;#8217;t get into that here. Besides, the team has already written a &lt;a href="http://datamapper.org/why.html"&gt;great summary of why DataMapper rocks&lt;/a&gt;. Read it. Oh, and performance kicks ass now too.&lt;/p&gt;
&lt;p&gt;OK, anyway. Tutorial time. Found your plastic hat? Good. Let&amp;#8217;s go. First let&amp;#8217;s get the gems we&amp;#8217;ll need. As of this writing, DM is at v0.2.3 and Sinatra is at v0.1.7. We&amp;#8217;re also going to retrieve the &lt;a href="http://syntaxi.rubyforge.org"&gt;Syntaxi&lt;/a&gt; gem, which we&amp;#8217;ll use for syntax highlighting.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo gem install sinatra datamapper json syntaxi -y&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since DM uses the &lt;a href="http://dataobjects.devjavu.com/"&gt;DataObjects.rb&lt;/a&gt; drivers, you&amp;#8217;ll want to install them. They&amp;#8217;re packaged with the distribution. For our purposes here we&amp;#8217;re going to assume you&amp;#8217;re on MySQL but all the standard drivers are there, so don&amp;#8217;t fret. Change to your DM gem directory (mine is &lt;em&gt;/opt/local/lib/ruby/gems/1.8/gems/datamapper-0.2.3&lt;/em&gt;) and issue the following command. Ignore any warnings that are generated. If you&amp;#8217;re on OS X 10.5, you may want to check out &lt;a href="http://blog.heimidal.net/2007/10/30/installing-datamapper-on-leopard"&gt;Heimidal&amp;#8217;s blog&lt;/a&gt; for instructions.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo rake dm:install:mysql&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that our prerequisites are satisfied, let&amp;#8217;s get started by creating the file &lt;em&gt;toopaste.rb&lt;/em&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;require 'rubygems'
require 'sinatra'
require 'data_mapper'
require 'syntaxi'&lt;/code&gt;

&lt;code&gt;### SETUP&lt;/code&gt;

&lt;code&gt;DataMapper::Database.setup({
  :adapter  =&amp;gt; 'mysql',
  :host     =&amp;gt; 'localhost',
  :username =&amp;gt; 'root',
  :password =&amp;gt; '',
  :database =&amp;gt; 'toopaste_development'
})&lt;/code&gt;

&lt;code&gt;### MODELS&lt;/code&gt;

&lt;code&gt;class Snippet &amp;lt; DataMapper::Base
  property :body, :text
  property :created_at, :datetime
  property :updated_at, :datetime&lt;/code&gt;

&lt;code&gt;  validates_presence_of :body
  validates_length_of :body, :minimum =&amp;gt; 1&lt;/code&gt;

&lt;code&gt;  Syntaxi.line_number_method = 'floating'&lt;/code&gt;

&lt;code&gt;  def formatted_body
    html = Syntaxi.new("[code lang='ruby']#{self.body}[/code]").process
    "&amp;lt;div class=\"syntax syntax_ruby\"&amp;gt;#{html}&amp;lt;/div&amp;gt;"
  end
end&lt;/code&gt;

&lt;code&gt;database.table_exists?(Snippet) or database.save(Snippet)&lt;/code&gt;

&lt;code&gt;### CONTROLLER ACTIONS&lt;/code&gt;

&lt;code&gt;layout 'default.erb'&lt;/code&gt;

&lt;code&gt;# new
get '/' do
  erb :new, :layout =&amp;gt; 'default.erb'
end&lt;/code&gt;

&lt;code&gt;# create
post '/' do
  @snippet = Snippet.new(:body =&amp;gt; params[:snippet_body])
  if @snippet.save
    redirect "/#{@snippet.id}"
  else
    redirect '/'
  end
end&lt;/code&gt;

&lt;code&gt;# show
get '/:id' do
  @snippet = Snippet.find(params[:id])
  erb :show, :layout =&amp;gt; 'default.erb'
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next we&amp;#8217;ll dissect this code listing to give you a feel for how Sinatra and DataMapper work, and show the code listings for our views as we get to them.&lt;/p&gt;
&lt;p&gt;First of all, we define our database connection for DataMapper. Looks pretty similar to its AR equivalent, eh? Before we can run this we&amp;#8217;ll need to create the MySQL database mentioned in the source. You can create the toopaste_development database by issuing the following mysql command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mysqladmin -u root -p create toopaste_development&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#8217;re not going to define a migration here, as this is a very simple case, but DM does support migrations in case you&amp;#8217;re curious. We next define our model, Snippet, which inherits from DataMapper::Base. The validators we&amp;#8217;re specifying look familiar to anyone coming over from AR but the property declarations might look a little bit odd at first.. &lt;span class="caps"&gt;OMG&lt;/span&gt; I don&amp;#8217;t have to put comments in my source file to remind me what attributes are available on my models?!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;property :body, :text
property :created_at, :datetime
property :updated_at, :datetime&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;#8217;s like a little slice of heaven, isn&amp;#8217;t it?&lt;/p&gt;
&lt;p&gt;Skip over the formatted_body method for a moment and look at the line after the model class declaration that checks for pre-existence of the table. You&amp;#8217;ll note that if it&amp;#8217;s not found we call database.save with the model name as a parameter. This creates our table, with all the appropriate fields, as specified in the model.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;database.table_exists?(Snippet) or database.save(Snippet)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The formatted_body method is simple. It just takes the body of our snippet (a property on the model) and wraps it in some code that gives us pretty syntax highlighting and line numbering. Syntaxi leverages Jamis Buck&amp;#8217;s &lt;a href="http://syntax.rubyforge.org/"&gt;Syntax gem&lt;/a&gt; to mark up the specified code, wrapping &lt;span class="caps"&gt;CSS&lt;/span&gt; span tags around things that should be colored, adding line numbers, and some other goodies too. You&amp;#8217;ll see the &lt;span class="caps"&gt;CSS&lt;/span&gt; in our layout shortly.&lt;/p&gt;
&lt;p&gt;Another interesting DM optimization worth noting: by default, the text field (body) is lazily loaded. Text columns are expensive in databases, and by using lazy loading, we only access them when they&amp;#8217;re needed. This speeds things up significantly in most cases. However, if you don&amp;#8217;t like it, you can just pass a :lazy =&amp;gt; false option in the text column property declaration.&lt;/p&gt;
&lt;p&gt;Moving on to the controller actions, you&amp;#8217;ll see that routes and actions are intimately married in Sinatra. Although this isn&amp;#8217;t desirable for a larger application, it&amp;#8217;s great for quickie one-off web apps like this pastie project. We only have three actions and they&amp;#8217;re only ever available at these three &lt;span class="caps"&gt;URL&lt;/span&gt; patterns.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;get '/' do
  erb :new, :layout =&amp;gt; 'default.erb'
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first action displays a form to create a new paste, and it&amp;#8217;s always available at &amp;#8216;/&amp;#8217;, your application root. Note that it&amp;#8217;s a &lt;span class="caps"&gt;GET&lt;/span&gt; request. The body of this action renders the new.erb template, which should be in your views/ subdirectory. Instead of pulling in an external template, you could just stash your &lt;span class="caps"&gt;HTML&lt;/span&gt; inline here. This may work fine for dirt-simple applications but I prefer to keep it separate. Here&amp;#8217;s that first view, &lt;em&gt;/views/new.erb&lt;/em&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class="snippet"&amp;gt;
  &amp;lt;form action="/" method="POST"&amp;gt;
    &amp;lt;textarea name="snippet_body" id="snippet_body" rows="20"&amp;gt;&amp;lt;/textarea&amp;gt;
    &amp;lt;br/&amp;gt;&amp;lt;input type="submit" value="Save"/&amp;gt;
  &amp;lt;/form&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next action is analogous to a #create action in RESTful Rails. The action is requested by a &lt;span class="caps"&gt;POST&lt;/span&gt; to the application root. Sinatra supports the standard &lt;span class="caps"&gt;GET&lt;/span&gt; and &lt;span class="caps"&gt;POST&lt;/span&gt; &lt;span class="caps"&gt;HTTP&lt;/span&gt; methods as well as &lt;span class="caps"&gt;PUT&lt;/span&gt; and &lt;span class="caps"&gt;DELETE&lt;/span&gt;, meaning that you can build RESTful applications with it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;post '/' do
  @snippet = Snippet.new(:body =&amp;gt; params[:snippet_body])
  if @snippet.save
    redirect "/#{@snippet.id}"
  else
    redirect '/'
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty standard stuff, right? We retrieve the parameter posted from the submit action in the new paste form, instantiate a new model and try to save it. If the validations pass, we redirect to the #show action equivalent. If not, we&amp;#8217;re just going to dump you back to the #new form again. Since the only way the action will fail is if the body property is empty, we&amp;#8217;re not going to bother with any sort of error message at this time. We&amp;#8217;re not rendering anything here (merely redirecting), so no template is required.&lt;/p&gt;
&lt;p&gt;If our post is successful, we&amp;#8217;re going to be taken to the #show action, which lives at /:id, where :id is the primary key of the corresponding database record. This action will also get accessed directly when you paste that &lt;span class="caps"&gt;URL&lt;/span&gt; to the chat room, and people click to view your code.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;get '/:id' do
  @snippet = Snippet.find(params[:id])
  erb :show, :layout =&amp;gt; 'default.erb'
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the code listing above, we look up the particular snippet specified in params[:id] and set an instance variable. We then render an ERb template, which of course has access to that instance variable. Here&amp;#8217;s the code you&amp;#8217;ll want in &lt;em&gt;/views/show.erb&lt;/em&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class="snippet"&amp;gt;
  &amp;lt;div class="sbody" id="content"&amp;gt;&amp;lt;%= @snippet.formatted_body %&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div class="sdate"&amp;gt;Created on &amp;lt;%= @snippet.created_at.strftime("%B %d, %Y at %I:%M %p") %&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;br/&amp;gt;&amp;lt;a href="/"&amp;gt;New Paste!&amp;lt;/a&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&amp;#8217;ve been paying attention you&amp;#8217;ve noticed that both of our erb method calls (used to render an embedded ruby &lt;span class="caps"&gt;HTML&lt;/span&gt; view, you can also use &lt;a href="http://haml.hamptoncatlin.com/"&gt;haml&lt;/a&gt;) have specified a layout. That layout does the sorts of things a layout usually does; it sets up the page body, the title of the page, the styles, and so on. For completeness&amp;#8217; sake, we&amp;#8217;ll list it here:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;
&amp;lt;html xmlns="http://www.w3.org/1999/xhtml"&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;title&amp;gt;&amp;lt;%= @title || 'Toopaste!' %&amp;gt;&amp;lt;/title&amp;gt;
  &amp;lt;style&amp;gt;
    html {
      background-color: #eee;
    }
    .snippet {
      margin: 5px;
    }
    .snippet textarea, .snippet .sbody {
      border: 5px dotted #eee;
      padding: 5px;
      width: 700px;
      color: #fff;
      background-color: #333;
    }
    .snippet textarea {
      padding: 20px;
    }
    .snippet input, .snippet .sdate {
      margin-top: 5px;
    }&lt;/code&gt;

&lt;code&gt;    /* Syntax highlighting */
    #content .syntax_ruby .normal {}
    #content .syntax_ruby .comment { color: #CCC; font-style: italic; border: none; margin: none; }
    #content .syntax_ruby .keyword { color: #C60; font-weight: bold; }
    #content .syntax_ruby .method { color: #9FF; }
    #content .syntax_ruby .class { color: #074; }
    #content .syntax_ruby .module { color: #050; }
    #content .syntax_ruby .punct { color: #0D0; font-weight: bold; }
    #content .syntax_ruby .symbol { color: #099; }
    #content .syntax_ruby .string { color: #C03; }
    #content .syntax_ruby .char { color: #F07; }
    #content .syntax_ruby .ident { color: #0D0; }
    #content .syntax_ruby .constant { color: #07F; }
    #content .syntax_ruby .regex { color: #B66; }
    #content .syntax_ruby .number { color: #FF0; }
    #content .syntax_ruby .attribute { color: #7BB; }
    #content .syntax_ruby .global { color: #7FB; }
    #content .syntax_ruby .expr { color: #909; }
    #content .syntax_ruby .escape { color: #277; }
    #content .syntax {
      background-color: #333;
      padding: 2px;
      margin: 5px;
      margin-left: 1em;
      margin-bottom: 1em;
    }
    #content .syntax .line_number {
      text-align: right;
      font-family: monospace;
      padding-right: 1em;
      color: #999;
    }
  &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;%= yield %&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save that listing as &lt;em&gt;views/default.erb&lt;/em&gt;. The rendered page content will be inserted into this layout where it yields. And that&amp;#8217;s pretty much it. You can fire up your new Sinatra and DataMapper-powered application by issuing the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ruby toopaste.rb
== Sinatra has taken the stage on port 4567!&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sinatra sits on top of &lt;a href="http://mongrel.rubyforge.org/"&gt;Mongrel&lt;/a&gt;, making it super-easy to use (and thread-safe to boot!). If you open up a web browser and point it at http://localhost:4567 you&amp;#8217;ll see the results. You now have a fully functional (albeit slightly retarded) pastie clone with  syntax highlighting for Ruby code snippets. And the core logic is all contained in a single file, with a few external ERb templates for cleanliness.&lt;/p&gt;
&lt;p&gt;If you like, you can &lt;a href="http://paste.zerosum.org"&gt;play with the finished app&lt;/a&gt; or &lt;a href="http://blog.zerosum.org/assets/2007/11/4/toopaste.zip"&gt;download the sources&lt;/a&gt;. Enjoy, and please comment if you have any problems or suggestions for improvement. This code was written and tested on OS X 10.4 and Debian Etch.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;UPDATED&lt;/span&gt; 07/02/08:&lt;/strong&gt; I finally got around to updating this tutorial for DataMapper 0.9.2. About time, eh? Click &lt;a href="http://blog.zerosum.org/2008/7/2/clone-pastie-with-sinatra-datamapper-redux"&gt;here&lt;/a&gt; to see the new version.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Blog Updates</title>
   <link href="http://blog.zerosum.org/2007/11/1/blog-updates.html" />
   <published>2007-11-01T00:00:00-04:00</published>
   <updated>2007-11-01T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/11/1/blog-updates</id>
   <content type="html">&lt;p&gt;So I finally got around to migrating the blog site over to &lt;a href="http://mephistoblog.com"&gt;Mephisto&lt;/a&gt;. I&amp;#8217;ve only been planning on doing that for like 9 months. Horray for progress!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Links For 10.30.07</title>
   <link href="http://blog.zerosum.org/2007/10/31/links-for-10-30-07.html" />
   <published>2007-10-31T00:00:00-04:00</published>
   <updated>2007-10-31T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/10/31/links-for-10-30-07</id>
   <content type="html">&lt;p&gt;&lt;img src="http://www.ruby-assn.org/ruby-logo.jpg" style="float: right"/&gt;Not-so-random things you need to know about:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.ruby-assn.org/logo-contest.html.en"&gt;New Ruby Logo Unveiled&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.netbeans.org/community/releases/60/"&gt;NetBeans 6.0 Beta 2 Released&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://datamapper.org/"&gt;Datamapper &lt;span class="caps"&gt;ORM&lt;/span&gt;&lt;/a&gt; (add Merb, stir, &amp;amp; bake at 300 for gooey goodness)&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://evang.eli.st/sinatra_and_git.mov"&gt;Git + Sinatra Web Framework&lt;/a&gt; (great screencast!)&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.robbyonrails.com/articles/2007/10/27/using-macports-ruby-and-rails-after-upgrading-to-os-x-leopard"&gt;Using MacPorts Ruby and Rails after Upgrading to OS X Leopard&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://www.microplace.com/"&gt;Microplace&lt;/a&gt; (eBay-backed microfinance on Rails)&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.techcrunch.com/2007/10/30/details-revealed-google-opensocial-to-be-common-apis-for-building-social-apps/"&gt;Google OpenSocial&lt;/a&gt; to Launch on Thursday?&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Startupping Contests</title>
   <link href="http://blog.zerosum.org/2007/10/30/startupping-contests.html" />
   <published>2007-10-30T00:00:00-04:00</published>
   <updated>2007-10-30T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/10/30/startupping-contests</id>
   <content type="html">&lt;p&gt;So Ty and I submitted our startup project&amp;#8217;s pitch to the &lt;a href="http://www.amazon.com/b?ie=UTF8&amp;node=377634011"&gt;Amazon Startup Challenge&lt;/a&gt; last night. Wish us luck!&lt;/p&gt;
&lt;p&gt;The idea (currently implemented as a working prototype, albeit with a number of rough edges) has to do with &lt;a href="http://en.wikipedia.org/wiki/Micropatronage"&gt;micropatronage&lt;/a&gt;, a concept that is near and dear to my heart. In a nutshell we believe that content authors should be rewarded for their efforts, and we think we&amp;#8217;re on to a way to make that fun and rewarding for patrons too.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s something we&amp;#8217;ve been developing on and off for months now, in between various other client gigs and open source initiatives. We have no illusions about being chosen (although it sure would be nice if we were!), but if nothing else the contest has given us the kick in the butt that we needed to get back on track with it and formalize a number of principles in writing. Writing things down, and trying to explain them to people whom you&amp;#8217;ve never met before, always helps to clarify your vision. It&amp;#8217;s quite amazing, really.&lt;/p&gt;
&lt;p&gt;Anyway, I love seeing contests like this, even when I don&amp;#8217;t win (which is most of the time). I thoroughly enjoyed my role as an organizer of the Rails Rumble event we ran in September, and I look forward to similarly-minded events like the upcoming &lt;a href="http://blitzweekend.com/"&gt;BlitzWeekend&lt;/a&gt; (hi Heri!), and even the more VC-involved &amp;#8220;contests&amp;#8221; like &lt;a href="http://www.seedcamp.com/"&gt;Seedcamp&lt;/a&gt; and of course &lt;a href="http://www.ycombinator.com"&gt;Y Combinator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I particularly enjoy following startup contests and events where creativity is a key factor; where instead of just implementing a common spec to see who can do it fastest or &amp;#8220;best&amp;#8221;, teams are actually challenged to invent something totally new, implement it, throw it against a wall and see if it sticks. Hey, now that&amp;#8217;s entrepreneurial; it&amp;#8217;s brave, it&amp;#8217;s somewhat reckless (in it&amp;#8217;s purest form, anyway), and it&amp;#8217;s a great way to hatch new disruptive ideas in front of a live audience.&lt;/p&gt;
&lt;p&gt;Some of the projects will be great, most of them will suck, but everyone will learn something. It&amp;#8217;s important to remember, too, that the &amp;#8220;winning&amp;#8221; team won&amp;#8217;t necessarily be the long term winner &amp;#8212; it&amp;#8217;s a distance running event, not a short sprint. In the end, it&amp;#8217;s all about development &amp;#8212; and I mean that in the personal growth sense, not in the geeks-behind-glass sense.&lt;/p&gt;
&lt;p&gt;Of course, you don&amp;#8217;t need a contest or money or really anything at all to go invent something new, especially these days when launching a company doesn&amp;#8217;t cost anything more than the skills, free time, and a &lt;span class="caps"&gt;VPS&lt;/span&gt;. But sometimes a little extra motivation goes a long way.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>JQueryCamp Is Tomorrow!</title>
   <link href="http://blog.zerosum.org/2007/10/26/jquerycamp-is-tomorrow.html" />
   <published>2007-10-26T00:00:00-04:00</published>
   <updated>2007-10-26T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/10/26/jquerycamp-is-tomorrow</id>
   <content type="html">&lt;p&gt;For anyone who&amp;#8217;s registered (and presumably in or around the greater Boston area), don&amp;#8217;t forget that &lt;a href="http://docs.jquery.com/JQueryCamp07"&gt;JQueryCamp&lt;/a&gt; is tomorrow! I&amp;#8217;ll be there, and looking forward to talks by John Resig, Yehuda Katz (whom I probably owe a beer), and many others.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Git Your Learn On</title>
   <link href="http://blog.zerosum.org/2007/10/22/git-your-learn-on.html" />
   <published>2007-10-22T00:00:00-04:00</published>
   <updated>2007-10-22T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/10/22/git-your-learn-on</id>
   <content type="html">&lt;p&gt;Any post about Git pretty much mandates the use of some lame pun in the title, and this blog entry is no exception. For those of you who are as-of-yet unfamiliar with it, &lt;a href="http://git.or.cz/"&gt;Git&lt;/a&gt; is a distributed version control system created by Linus Torvalds. It&amp;#8217;s been around and usable for about a year now, but I&amp;#8217;d only been peripherally aware of it until &lt;a href="http://www.youtube.com/watch?v=4XpnKHJAok8"&gt;recently&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the past I&amp;#8217;ve just used it to check out and occaisionally toy with the latest &lt;a href="http://rubini.us/"&gt;Rubinius&lt;/a&gt; sources but now that the &lt;a href="http://reinh.com/2007/10/15/project-offtrac"&gt;Offtrac&lt;/a&gt; project is using it, it finally looks like I&amp;#8217;m going to have to start familiarizing myself with it beyond installation and cloning a remote repository. If that sounds negative it isn&amp;#8217;t meant to be; I enjoy being forced to learn new things every once in a while. Srsly.&lt;/p&gt;
&lt;p&gt;[To be honest I&amp;#8217;m still relatively happy with Subversion, but hey, when I started using Subversion I was still at least relatively happy with &lt;span class="caps"&gt;CVS&lt;/span&gt; too. No wait, scratch that, I hated &lt;span class="caps"&gt;CVS&lt;/span&gt;.]&lt;/p&gt;
&lt;p&gt;Anyway, for those of you out there like me who are just getting acquainted with Git and particularly those who are stumbling over the implications of the &lt;em&gt;distributed&lt;/em&gt; part of &lt;em&gt;distributed version control&lt;/em&gt;, Carl Worth has written a useful &lt;a href="http://cworth.org/hgbook-git/tour/"&gt;getting started guide&lt;/a&gt; that you should definitely check out. Of course there&amp;#8217;s the &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/user-manual.html"&gt;official user guide&lt;/a&gt; too.&lt;/p&gt;
&lt;p&gt;In practice, normal usage really isn&amp;#8217;t as different as it seems, and the concept of a distributed repository is a truly powerful one. Everyone has commit access to &lt;em&gt;their own local branch&lt;/em&gt;, which means most operations are fast, and the centralized who-gets-commit-rights question becomes a total non-issue. That&amp;#8217;s very very cool. Oh, and no .svn folders littered in every folder is another nicety. The jury&amp;#8217;s still out for me as of right now, which is to say I&amp;#8217;m not rushing to switch all my existing Subversion projects over just yet. But I have to say, I&amp;#8217;m very intrigued so far.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>718-123-2083</title>
   <link href="http://blog.zerosum.org/2007/10/22/718-123-2083.html" />
   <published>2007-10-22T00:00:00-04:00</published>
   <updated>2007-10-22T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/10/22/718-123-2083</id>
   <content type="html">&lt;p&gt;Someone rings my cell phone at 7AM this morning and asks &amp;#8220;is this Nicholas&amp;#8221;? I answer &amp;#8220;yes&amp;#8221;, because well, that&amp;#8217;s my name. Then they hang up.&lt;/p&gt;
&lt;p&gt;Apparently &lt;a href="http://800notes.com/Phone.aspx/1-718-123-2083"&gt;I&amp;#8217;m not the only one&lt;/a&gt; this has happened to. Isn&amp;#8217;t it good to know that there are communities for just about everything on teh Interwebs, including strange paranoia-inducing phone spam? But just who the fsck are these people anyway, and what in the world was the purpose of that? Sigh.&lt;/p&gt;
&lt;p&gt;In unrelated but positive news, the Sox destroyed the Indians last night 11 to 2, winning the &lt;span class="caps"&gt;ALCS&lt;/span&gt;. Yes, I am a fair weather fan.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Where's Nap?</title>
   <link href="http://blog.zerosum.org/2007/10/12/where-s-nap.html" />
   <published>2007-10-12T00:00:00-04:00</published>
   <updated>2007-10-12T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/10/12/where-s-nap</id>
   <content type="html">&lt;p&gt;Things have been kind of crazy lately, and blog updates have been few and far between. Sorry about that, it&amp;#8217;s  not that I&amp;#8217;ve run out of things to say. Honest.&lt;/p&gt;
&lt;p&gt;The truth of the matter is I&amp;#8217;ve just been really busy with a couple client projects, and some other goodies that I&amp;#8217;ll (hopefully) be writing about soon. And oh, yeah, I&amp;#8217;m getting married this weekend too ;-).&lt;/p&gt;
&lt;p&gt;So actually, the answer to the titular question is Martha&amp;#8217;s Vineyard, where my lovely wife-to-be and I are renting a house for the week. It&amp;#8217;s great to get away from (almost) everything for a little while.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rails 2.0 Preview Release Available</title>
   <link href="http://blog.zerosum.org/2007/10/1/rails-2-0-preview-release-available.html" />
   <published>2007-10-01T00:00:00-04:00</published>
   <updated>2007-10-01T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/10/1/rails-2-0-preview-release-available</id>
   <content type="html">&lt;p&gt;Check it out: a &lt;a href="http://weblog.rubyonrails.com/2007/9/30/rails-2-0-0-preview-release"&gt;Preview Release&lt;/a&gt; of Rails 2.0 was made available yesterday. Things are &amp;#8220;almost finished&amp;#8221; and this is an opportunity for folks (who haven&amp;#8217;t been following edge closely) to get a taste of what&amp;#8217;s new before the final release. To install the gem:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gem install rails --source http://gems.rubyonrails.org&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or you can freeze edge using the tag &amp;#8220;rel_2-0-0_PR&amp;#8221;. Make sure to check out that post (linked above) to read about all the good stuff.&lt;/p&gt;
&lt;p&gt;Note that 1.2.4 will also be released prior to 2.0 and will include a variety of bugfixes as well as the final deprecation warnings for upgrading an application to 2.0. Big thanks to the whole core team (and all the contributors) for their excellent work.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Presenting @ Ruby East</title>
   <link href="http://blog.zerosum.org/2007/9/28/presenting-ruby-east.html" />
   <published>2007-09-28T00:00:00-04:00</published>
   <updated>2007-09-28T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/9/28/presenting-ruby-east</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m going to be at &lt;a href="http://www.ruby-east.com"&gt;Ruby East&lt;/a&gt; on &amp;#8212; oh wow, I&amp;#8217;m already here. Hrmm, well nevermind then. Obviously things have been much too busy for pro-active blog entries lately. Sorry about that.&lt;/p&gt;
&lt;p&gt;In any case, if you&amp;#8217;re here, make sure to hang around until the end to see my Rails Rumble talk, which will include announcing the winners. We&amp;#8217;ll also be showing some of the team screencasts, in order to demonstrate just how much you can accomplish with Ruby in a very short amount of time. Should be a fun way to close out the event.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re not lucky enough to be attending this great little regional conference, the winning teams will also be announced on the &lt;a href="http://www.railsrumble.com"&gt;Rumble Blog&lt;/a&gt; sometime later today. Great work everyone.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>NetBeans 6.0 Beta 1 Available</title>
   <link href="http://blog.zerosum.org/2007/9/19/netbeans-6-0-beta-1-available.html" />
   <published>2007-09-19T00:00:00-04:00</published>
   <updated>2007-09-19T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/9/19/netbeans-6-0-beta-1-available</id>
   <content type="html">&lt;p&gt;NetBeans 6.0 Beta 1 is out and ready for download, including a slimmed-down Ruby-only version for those of you who don&amp;#8217;t want all the extras. Personally I like having one &lt;span class="caps"&gt;IDE&lt;/span&gt; for both Java and Ruby but hey, I&amp;#8217;m special. As I&amp;#8217;ve written about before, I&amp;#8217;m quite smitten with NetBeans and this latest release is the best yet. If you&amp;#8217;re curious about why I&amp;#8217;m gushing over it, read &lt;a href="http://wiki.netbeans.info/wiki/view/RubyOnRails"&gt;here&lt;/a&gt;, &lt;a href="http://lifeonrails.org/2007/8/30/netbeans-the-best-ruby-on-rails-ide"&gt;here&lt;/a&gt;, and &lt;a href="http://headius.blogspot.com/2007/08/netbeans-ruby-support-is-bomb.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So yeah, it&amp;#8217;s nice. Go &lt;a href="http://bits.netbeans.org/download/6_0/beta1/latest/"&gt;download 6.0 Beta 1&lt;/a&gt; and give it a try. It&amp;#8217;s packaged with &lt;a href="http://jruby.codehaus.org/"&gt;JRuby 1.0.1&lt;/a&gt; and Glassfish v2, which is starting to look more and more attractive as a serious deployment option for Rails.&lt;/p&gt;
&lt;p&gt;PS: those of you who are frustrated with Goldspike may want to take a look at &lt;a href="http://blog.nicksieger.com/articles/2007/09/04/warbler-a-little-birdie-to-introduce-your-rails-app-to-java"&gt;Nick Sieger&amp;#8217;s Warbler&lt;/a&gt;, an alternative for packaging up your &lt;span class="caps"&gt;WAR&lt;/span&gt; files.&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;PPS&lt;/span&gt;: you don&amp;#8217;t have to use JRuby as your interpreter of course. Just go to preferences &amp;#8594; Ruby and point it at &lt;span class="caps"&gt;MRI&lt;/span&gt; (/usr/bin/ruby or whatever) if you don&amp;#8217;t want / need / like JRuby. And then you can use the fast debugger too. Inline Ruby debugging rocks.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rock The (Rumble) Vote</title>
   <link href="http://blog.zerosum.org/2007/9/15/rock-the-rumble-vote.html" />
   <published>2007-09-15T00:00:00-04:00</published>
   <updated>2007-09-15T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/9/15/rock-the-rumble-vote</id>
   <content type="html">&lt;p&gt;We launched the Voting portion of the Rails Rumble on Thursday evening, and so far it&amp;#8217;s been a tremendous hit. Almost 4000 unique votes have been recorded in less than two days. If you check out &lt;a href="http://vote.railsrumble.com"&gt;vote.railsrumble.com&lt;/a&gt; you can view the current top 10 ranked applications as well as a smattering of random entries.&lt;/p&gt;
&lt;p&gt;I want to reiterate once again that I&amp;#8217;ve been overwhelmed with the creativity and polish that are reflected in a lot of these entries. Many of them look like the teams spent two months instead of two days. I&amp;#8217;m not going to name any names, but I definitely have my list of favorites.&lt;/p&gt;
&lt;p&gt;So anyway, get off your butt, register to vote, and help the community choose the best 48-hour app! You don&amp;#8217;t even have to go down to the local high school or anything. Woot! The voting period lasts two weeks, and wraps up on the 27th, after which winners will be announced at the &lt;a href="http://www.ruby-east.com"&gt;Ruby East&lt;/a&gt; conference. Maybe I&amp;#8217;ll see you there?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Overlooking The Obvious</title>
   <link href="http://blog.zerosum.org/2007/9/14/overlooking-the-obvious.html" />
   <published>2007-09-14T00:00:00-04:00</published>
   <updated>2007-09-14T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/9/14/overlooking-the-obvious</id>
   <content type="html">&lt;p&gt;Sometimes we overlook the obvious. This had me scratching my head for a good 15 minutes yesterday. I&amp;#8217;ll blame it on the plague (aka nasty cold) that I seem to have contracted.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt; format = "%A, %B %d %Y"
=&amp;gt; "%A, %B %d %Y"
&amp;gt;&amp;gt; monday = Time.now.beginning_of_week
=&amp;gt; Mon Sep 10 00:00:00 -0400 2007
&amp;gt;&amp;gt; monday.strftime(format)
=&amp;gt; "Monday, September 10 2007"
&amp;gt;&amp;gt; (monday+6.weeks).strftime(format)
=&amp;gt; "Monday, October 22 2007"
&amp;gt;&amp;gt; (monday+12.weeks).strftime(format)
=&amp;gt; "Sunday, December 02 2007"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Huh? Exactly 12 weeks from Monday is Sunday? &lt;span class="caps"&gt;WTF&lt;/span&gt;?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt; monday + 12.weeks
=&amp;gt; Sun Dec 02 23:00:00 -0500 2007
&amp;gt;&amp;gt; (monday + 12.weeks).dst?
=&amp;gt; false
&amp;gt;&amp;gt; monday.dst?
=&amp;gt; true&lt;/code&gt;

&lt;code&gt;Three letters: &amp;lt;a href="http://en.wikipedia.org/wiki/Daylight_savings_time"&amp;gt;D S T&amp;lt;/a&amp;gt;. Heh.
&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Can You Feel The Rumble?</title>
   <link href="http://blog.zerosum.org/2007/9/8/can-you-feel-the-rumble.html" />
   <published>2007-09-08T00:00:00-04:00</published>
   <updated>2007-09-08T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/9/8/can-you-feel-the-rumble</id>
   <content type="html">&lt;p&gt;&lt;img src="http://www.railsrumble.com/images/badges/railsrumble_blue_160.png" style="float: right;"/&gt;So the &lt;a href="http://www.railsrumble.com"&gt;Rails Rumble&lt;/a&gt; is on! We&amp;#8217;ve worked pretty hard to hook this up and it&amp;#8217;s great to see it alive and breathing, and #railsrumble buzzing with activity. There were some capacity issues at first (ouch!) but things seem to be going pretty smoothly now.&lt;/p&gt;
&lt;p&gt;Greets to Carter Parks, Rodrigo Kochenburger, and Erin &amp;amp; Tommy Shine, who all poured a lot of precious blood into this beastie. And our friends Chris Aker and Tom Asaro at &lt;a href="http://www.linode.com"&gt;Linode&lt;/a&gt;. And our other sponsors too, of course. Oh, and best of luck to all the Rumblers. Launch some cool-ass web properties and win some swag, guys! Hope you&amp;#8217;ve got plenty of Red Bull to keep you caffeinated.&lt;/p&gt;
&lt;p&gt;Me? I&amp;#8217;m going to bed. See you tomorrow in &lt;span class="caps"&gt;IRC&lt;/span&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Moving to Nginx and Cap2.0</title>
   <link href="http://blog.zerosum.org/2007/8/27/moving-to-nginx-and-cap2-0.html" />
   <published>2007-08-27T00:00:00-04:00</published>
   <updated>2007-08-27T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/8/27/moving-to-nginx-and-cap2-0</id>
   <content type="html">&lt;p&gt;So a few months back I started using &lt;a href="http://nginx.net/"&gt;nginx&lt;/a&gt; on my staging server, front-ending for Mongrel, and just recently I&amp;#8217;ve stated migrating some production stuff over to it. It&amp;#8217;s pretty great as a lightweight Apache replacement. Incredibly simple syntax, very quick and close to the bone. Most of my production stuff still runs on Apache, but that may soon be changing. I also finally made the leap to &lt;a href="http://www.capify.org/upgrade"&gt;Capistrano 2.0&lt;/a&gt;. Loving the new namespaced task hierarchy.&lt;/p&gt;
&lt;p&gt;Anyway, here&amp;#8217;s a simple alternative maintenance page recipe for Capistrano&amp;#8217;s deploy:web:disable target and the corresponding Nginx config to make use of it. In case you&amp;#8217;re unfamiliar with it, the disable web task basically redirects all requests to a maintenance page until deploy:web:enable is run, which returns things to normal. This recipe assumes you&amp;#8217;ve created your own (static) maintenance.html page in public/maintenance.html and that it makes use of existing stylesheets and images &amp;#8212; meaning that you don&amp;#8217;t want to rewrite those requests.&lt;/p&gt;
&lt;p&gt;in config/deploy.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;namespace :deploy do
  desc "Disable requests to the app, show maintenance page"
  web.task :disable, :roles =&amp;gt; :web do
    run "cp #{current_path}/public/maintenance.html  #{shared_path}/system/maintenance.html"
  end&lt;/code&gt;

&lt;code&gt;  desc "Re-enable the web server by deleting any maintenance file"
  web.task :enable, :roles =&amp;gt; :web do
    run "rm #{shared_path}/system/maintenance.html"
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;in nginx.conf (within your server block definition):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# allow requests for images, js, css, and icons to go through
# even if cap has been used to disable the site
if ($request_filename ~* /(images|javascripts|stylehseets)/) { break; }
if ($request_filename ~* \.ico$) { break; }&lt;/code&gt;

&lt;code&gt;# for cap's deploy:web:disable task
if (-f $document_root/system/maintenance.html) {
    rewrite ^(.*)$ /system/maintenance.html last;
    break;
}
&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>NHRuby: Shoes. And Belts. And You!</title>
   <link href="http://blog.zerosum.org/2007/8/21/nhruby-shoes-and-belts-and-you.html" />
   <published>2007-08-21T00:00:00-04:00</published>
   <updated>2007-08-21T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/8/21/nhruby-shoes-and-belts-and-you</id>
   <content type="html">&lt;p&gt;If you&amp;#8217;re in the greater NH/Maine/Mass seacoast area, don&amp;#8217;t forget to check out tomorrow&amp;#8217;s &lt;a href="http://wiki.nhruby.org"&gt;NHRuby&lt;/a&gt; group. Sir Brian DeLacey will be visiting us from Boston and talking about &lt;a href="http://code.whytheluckystiff.net/shoes/"&gt;Shoes&lt;/a&gt;, the Ruby desktop UI toolkit from the ever-enigmatic &lt;a href="http://www.whytheluckystiff.net/"&gt;_why&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If there&amp;#8217;s time left to spare, I&amp;#8217;ll probably spend some time blathering on about how you should participate in the upcoming &lt;a href="http://www.railsrumble.com"&gt;Rails Rumble&lt;/a&gt;. Believe me, after seeing some of the prizes, you&amp;#8217;re going to want to get in on the action. I was dead f**king serious about that championship belt. You&amp;#8217;ll see.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>NetBeans Rocks</title>
   <link href="http://blog.zerosum.org/2007/8/17/netbeans-rocks.html" />
   <published>2007-08-17T00:00:00-04:00</published>
   <updated>2007-08-17T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/8/17/netbeans-rocks</id>
   <content type="html">&lt;p&gt;NetBeans really is the &lt;span class="caps"&gt;BOMB&lt;/span&gt;, as &lt;a href="http://headius.blogspot.com/2007/08/netbeans-ruby-support-is-bomb.html"&gt;Charles Nutter&lt;/a&gt; notes over on &lt;a href="http://headius.blogspot.com/2007/08/netbeans-ruby-support-is-bomb.html"&gt;his blog&lt;/a&gt;. Check out that link. I wanted to make sure I echoed his thoughts here, because for me, NetBeans really is the best Rails &lt;span class="caps"&gt;IDE&lt;/span&gt; on the planet. I switched over from IntelliJ some time ago and haven&amp;#8217;t regretted it even briefly.&lt;/p&gt;
&lt;p&gt;I really can&amp;#8217;t say enough things about NetBeans. What other &lt;span class="caps"&gt;IDE&lt;/span&gt; makes it painless to debug (yes debug, within the &lt;span class="caps"&gt;IDE&lt;/span&gt;), refactor, and test your Ruby applications? Plus, the syntax highlighting is rockin and you get all the standard NetBeans goodness out of the box. Don&amp;#8217;t want a huge download? No big deal, there&amp;#8217;s a &lt;a href="http://deadlock.netbeans.org/hudson/job/ruby/"&gt;slimmed-down Ruby-only version&lt;/a&gt; available. Give it a shot. Even if you&amp;#8217;re a hardcore Textmate geek, I think you&amp;#8217;ll at least be able to see why I&amp;#8217;m raving about it.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Get Ready To Rumble</title>
   <link href="http://blog.zerosum.org/2007/8/10/get-ready-to-rumble.html" />
   <published>2007-08-10T00:00:00-04:00</published>
   <updated>2007-08-10T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/8/10/get-ready-to-rumble</id>
   <content type="html">&lt;p&gt;&lt;img src="http://www.railsrumble.com/images/badges/railsrumble_black_160.png" style="float: right;"/&gt;So like everyone else, you probably have a killer web app idea you&amp;#8217;ve been sitting on. Maybe you&amp;#8217;ve thought about building it, maybe you&amp;#8217;ve even drawn out some diagrams on the back of a napkin, but you just haven&amp;#8217;t found the time to execute it. The unfortunate reality is that sometimes you just need an excuse, or a little push, to get something awesome started.&lt;/p&gt;
&lt;p&gt;Sound about right? Then this one&amp;#8217;s for you. Enter the &lt;a href="http://www.railsrumble.com"&gt;Rails Rumble&lt;/a&gt;, September 8-9, and consider yourself pushed.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Ruby, Rails, Micropayments, and Amazon FPS</title>
   <link href="http://blog.zerosum.org/2007/8/8/ruby-rails-micropayments-and-amazon-fps.html" />
   <published>2007-08-08T00:00:00-04:00</published>
   <updated>2007-08-08T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/8/8/ruby-rails-micropayments-and-amazon-fps</id>
   <content type="html">&lt;p&gt;Last week Amazon unveiled a beta of their new &lt;a href="http://www.amazon.com/b?ie=UTF8&amp;node=342430011"&gt;Flexible Payments Service&lt;/a&gt;, a potential Paypal-killer and Google Checkout-killer, among other things. At first glance, &lt;span class="caps"&gt;FPS&lt;/span&gt; seems to be everything that Paypal isn&amp;#8217;t: well designed, &lt;span class="caps"&gt;API&lt;/span&gt;-centric, and built with developers in mind.&lt;/p&gt;
&lt;p&gt;While everyone is busy barking about how Amazon is going to go head to head with Google Checkout and Paypal for purchases, they seem to be missing the more interesting development here. I&amp;#8217;m talking about something that neither Paypal or Google are even attempting to do, as far as I know: micropayments.&lt;/p&gt;
&lt;p&gt;Ty, Steve, and I spent some serious time putting together a few different iterations of an idea/prototype earlier this year, that involves micropayments and the street performer protocol. And some other stuff, too :-). Unfortunately, when it came time to tie it into a payment gateway, it became painfully obvious that what we needed didn&amp;#8217;t really exist, so we compromised. And that compromise led to a bunch of problems and eventually what we felt was an unworkable solution. So it&amp;#8217;s been in mothballs since. This looks like it could be what we were maybe waiting for.&lt;/p&gt;
&lt;p&gt;If you check out Amazon&amp;#8217;s rate schedule you can see why I&amp;#8217;m excited:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For Amazon Payments balance transfers &amp;lt; $0.05: &lt;br /&gt;
20% of the transaction amount, with a minimum fee of $0.0025&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;OK, OK, so 20% is a hefty fee but not when we&amp;#8217;re talking about the alternative being somewhere in the neighborhood of $0.30 &lt;span class="caps"&gt;USD&lt;/span&gt; + 2-3%. So yeah, pfft. This is &lt;span class="caps"&gt;HUGE&lt;/span&gt;. And yes, it does look like these micropayments only work when you&amp;#8217;re using Amazon payments (as opposed to using a credit card, etc) but so what? I&amp;#8217;m not so sure that&amp;#8217;s an obstacle.&lt;/p&gt;
&lt;p&gt;Another reason it&amp;#8217;s so interesting to me is that they&amp;#8217;ve decided to support three languages/platforms in their initial beta rollout: Java, &lt;span class="caps"&gt;PHP&lt;/span&gt;, and yes, my friends, Ruby. Oh, and the &lt;a href="http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=126"&gt;sample app&lt;/a&gt;? Yep. Rails.&lt;/p&gt;
&lt;p&gt;Why aren&amp;#8217;t we more excited about this?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Impressed With Comatose CMS</title>
   <link href="http://blog.zerosum.org/2007/7/24/impressed-with-comatose-cms.html" />
   <published>2007-07-24T00:00:00-04:00</published>
   <updated>2007-07-24T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/7/24/impressed-with-comatose-cms</id>
   <content type="html">&lt;p&gt;Often after I&amp;#8217;m finished building the bulk of a web app, I find there are some secondary pages that need to be built. These pages are largely informational, such as an about page, a contact page, an &lt;span class="caps"&gt;FAQ&lt;/span&gt;, etc. They&amp;#8217;re relatively static in terms of the content, but it&amp;#8217;s always nice if we can supply our client (or ourselves) with a nice &lt;span class="caps"&gt;CMS&lt;/span&gt;-style interface to make updating them easy, and within the context of our existing application layouts. Keep it simple, keep it &lt;span class="caps"&gt;DRY&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The obvious thing is to cook up some sort of PagesController from scratch. This is nice because it&amp;#8217;ll make use of your existing facilities, your authentication/authorization system, layouts, etc. It is custom, after all, and a custom fit is almost always the best fit. But it&amp;#8217;s a fair bit of work for something that&amp;#8217;s probably not &amp;#8216;core&amp;#8217; to the application, and takes cycles away from other places they could be better spent.&lt;/p&gt;
&lt;p&gt;On the other hand, you can integrate with a 3rd-party &lt;span class="caps"&gt;CMS&lt;/span&gt; or blogging package like Typo, Radiant &lt;span class="caps"&gt;CMS&lt;/span&gt;, or Mephisto. They&amp;#8217;re all great packages and do what they do really well. The downside is you&amp;#8217;ve got to write a fair amount of glue to hook everything together and make it look (and feel) uniform.&lt;/p&gt;
&lt;p&gt;Another option is to use Matt McCray&amp;#8217;s &lt;a href="http://comatose.rubyforge.org/"&gt;Comatose&lt;/a&gt; plugin, a micro &lt;span class="caps"&gt;CMS&lt;/span&gt;. It&amp;#8217;s got all the basic functionality you want for this sort of stuff out of the box and it couldn&amp;#8217;t be much easier to use. The real bonus is integration is almost completely seemless, which makes it (imho) the best of both worlds for this sort of project.&lt;/p&gt;
&lt;p&gt;Installing the plugin gets you a ComatoseController and a ComatoseAdminController. You add an entry (or multiple entries, if you like) in your routes file to tell your application when to invoke the ComatoseController. You might prefer a scheme where all URLs starting with /pages are passed to Comatose, for example. Then you log into the admin controller (which also needs an entry in routes) to create the pages. All the basic management tools we need are here; pages are organized hierarchically and can be edited with great ease, using a variety of markup filters. Each page gets a number of attributes, including a title, keywords, author, etc.&lt;/p&gt;
&lt;p&gt;Basically it&amp;#8217;s everything we need for the bare-minimum no-frills &lt;span class="caps"&gt;CMS&lt;/span&gt; experience and nothing we don&amp;#8217;t. Which is just the way I like it. Check it out for your next project.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="caps"&gt;UPDATE&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Anyone having issues with Comatose and authentication should check out &lt;a href="http://code.google.com/p/comatose-plugin/issues/detail?id=5"&gt;this bug report&lt;/a&gt;. If you&amp;#8217;re specifying an alternate session key, you should put it in environment.rb instead of ApplicationController.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ActionController::Base.session_options[:session_key] = "_your_custom_session_id"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Comatose controllers inherit directly from ActionController::Base instead of from your application controller. So if you specify the session key in application.rb, the Comatose-driven sections of your app will be blissfully unaware of it. This means a method like logged_in? (which checks the session for your login status) will always report back as false.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Sidebar Login Box Recipe (restful_auth)</title>
   <link href="http://blog.zerosum.org/2007/7/13/sidebar-login-box-recipe-restful_auth.html" />
   <published>2007-07-13T00:00:00-04:00</published>
   <updated>2007-07-13T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/7/13/sidebar-login-box-recipe-restful_auth</id>
   <content type="html">&lt;p&gt;One of the nice features of Rick Olson&amp;#8217;s excellent &lt;a href="http://svn.techno-weenie.net/projects/plugins/restful_authentication/"&gt;restful_authentication plugin&lt;/a&gt; is the store_location facility. If you set up a :login_required before filter in your controller, the access_denied method will get called if the user isn&amp;#8217;t logged in. The requested &lt;span class="caps"&gt;URL&lt;/span&gt; will be stored in the session and the user will be redirected to the login page. After logging in, redirect_back_or_default is called by SessionController#create, which pulls the location out of the session and redirects the user back to where they intended to go in the first place. Very slick.&lt;/p&gt;
&lt;p&gt;However, if you&amp;#8217;ve built an application which has a login box in the sidebar (I recommend &lt;a href="http://agilewebdevelopment.com/plugins/simple_sidebar"&gt;simple_sidebar&lt;/a&gt;), restful_auth has no idea where you were coming from before the post to the create action. So you get redirected to the default (usually &amp;#8216;/&amp;#8217;) specified as a parameter to redirect_back_or_default. This isn&amp;#8217;t usually what the user expects. They expect to be returned to the page they were looking at before if they log in from the sidebar. Oh noes!&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s a little recipe you can use to provide that&amp;#8230;&lt;/p&gt;
&lt;p&gt;First, a simple change to authenticated_system.rb in your lib/ directory (this file is created by the authenticated generator). Change the store_location method to this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def store_location(location = request.request_uri)
  session[:return_to] = location
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before this change, store_location took 0 parameters and always set the return_to location to the current request &lt;span class="caps"&gt;URI&lt;/span&gt;. Now, we&amp;#8217;ve modified it so it can (optionally) take the location to store as a parameter. If this parameter isn&amp;#8217;t supplied, it defaults to the old behavior.&lt;/p&gt;
&lt;p&gt;Next, change the create method in your session controller so it checks the &lt;span class="caps"&gt;HTTP&lt;/span&gt; referer. Just add one tiny little line to the top of the method:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def create
  check_referer
  ...
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&amp;#8217;s write that check_referer method (it should be protected, not public):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def check_referer
  referer = request.env['HTTP_REFERER'] || ""
  if referer.match(request.domain) &amp;amp;&amp;amp;
    !referer.match(session_url) &amp;amp;&amp;amp;
    !referer.match(login_url)
      store_location(request.env['HTTP_REFERER'])
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What this little utility method does is check the &lt;span class="caps"&gt;HTTP&lt;/span&gt; referer. If the referer is from the current domain, and isn&amp;#8217;t the session#create &lt;span class="caps"&gt;URL&lt;/span&gt; or &amp;#8216;/login&amp;#8217; (in my application, there&amp;#8217;s a login_path named route), we go ahead and store the location of the &lt;strong&gt;referer&lt;/strong&gt;. This will later be plucked out by redirect_back_or_default. Note that you&amp;#8217;ll need to regex match to make sure the referer value isn&amp;#8217;t anything you don&amp;#8217;t want to store. For instance, if the user navigates to the login page directly and logs in from there, you don&amp;#8217;t want to redirect &lt;strong&gt;back&lt;/strong&gt; to the login page on success. You probably want to redirect to the default page, which is whatever you&amp;#8217;re specifying as the default with redirect_back_or_default.&lt;/p&gt;
&lt;p&gt;So that&amp;#8217;s it! An easy way to handle redirects from sidebar login blocks, without muddying the already elegantly designed redirects that happen when access is denied.&lt;/p&gt;
&lt;p&gt;If you want to write a functional test for this, try something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def test_redirect_to_referer # for login sidebar
  location = url_for(:controller =&amp;gt; 'foo', :action =&amp;gt; 'index')
  @request.env['HTTP_REFERER'] = location
  post :create, :login =&amp;gt; 'quentin', :password =&amp;gt; 'test'
  assert_response :redirect
  assert_redirected_to location
end
&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Swing Reduction Sauce</title>
   <link href="http://blog.zerosum.org/2007/7/12/swing-reduction-sauce.html" />
   <published>2007-07-12T00:00:00-04:00</published>
   <updated>2007-07-12T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/7/12/swing-reduction-sauce</id>
   <content type="html">&lt;p&gt;JRuby continues to develop in interesting ways. Earlier today, Zed Shaw (Mongrel&amp;#8217;s dad) announced the release of &lt;a href="http://archive.jruby.codehaus.org/user/20070711175226.30414472.zedshaw%40zedshaw.com"&gt;Profligacy 1.0&lt;/a&gt;, which you should take a look at if you&amp;#8217;ve got a thing for building cross-platform desktop apps in Ruby. It&amp;#8217;s pretty cool.&lt;/p&gt;
&lt;p&gt;Profligacy is a (wildly extravagant?) library that purports to take the pain out of using Swing components with JRuby. It uses &lt;span class="caps"&gt;LEL&lt;/span&gt;, &lt;a href="http://www.clarographics.org/layout_expression_language"&gt;Layout Expression Language&lt;/a&gt;, to bring a sort of wiki-ish flavor to component layout. This is truly bizarre at first glance, but damn cool at the same time. Basically the Ascii art you lay out with &lt;span class="caps"&gt;LEL&lt;/span&gt; translates into a Swing GroupLayout. Ah-wha? Yep. Check out some &lt;a href="http://ihate.rubyforge.org/profligacy/sample.html"&gt;examples&lt;/a&gt;. I told you it was cool.&lt;/p&gt;
&lt;p&gt;It also does some other neat stuff like auto-converting procs to Listener interfaces, but I won&amp;#8217;t go on about that, as you can go check the release notes instead. If you&amp;#8217;ve ever worked in Swing before, you know how painful it can be. Profligacy makes it significantly less bitter to swallow. Now stop reading blogs and go build your first cross-platform Ruby desktop app. You know you want to.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>An Introduction to Scraping with Hpricot</title>
   <link href="http://blog.zerosum.org/2007/6/30/an-introduction-to-scraping-with-hpricot.html" />
   <published>2007-06-30T00:00:00-04:00</published>
   <updated>2007-06-30T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/6/30/an-introduction-to-scraping-with-hpricot</id>
   <content type="html">&lt;p&gt;For one of my hobby projects, I&amp;#8217;ve been building a comic book release schedule webapp in Ruby. Obviously, a large part of that involves locating data sources for comic book publishers and importing those sources. Unfortunately, none of the major publishers have seen fit to make their release schedules available in &lt;span class="caps"&gt;RSS&lt;/span&gt; or Atom or an other structured format for that matter. Sigh.&lt;/p&gt;
&lt;p&gt;Fortunately, all is not lost. With the Hpricot gem and a little scraping know-how, we can overcome almost any parsing obstacle, as long as the data is in a somewhat predictably arranged state. Let&amp;#8217;s see how it works&amp;#8230;&lt;/p&gt;
&lt;p&gt;For our example, we&amp;#8217;ll consider &lt;a href="http://www.dccomics.com"&gt;DC Comics&lt;/a&gt;, home of Superman, Batman, Aquaman, and&amp;#8230; &lt;a href="http://en.wikipedia.org/wiki/Super-Chief"&gt;Super-Chief&lt;/a&gt; (Apache Chief? No, he&amp;#8217;s different). DC makes their weekly release schedule available through their website at &lt;a href="http://dccomics.com/comics/?dat=20070630"&gt;this &lt;span class="caps"&gt;URL&lt;/span&gt;&lt;/a&gt;. That&amp;#8217;s nice and convenient. But it&amp;#8217;d certainly be more convenient if they had a feed available. (If they &lt;strong&gt;do&lt;/strong&gt; have a feed available, hidden deep within their website, and I haven&amp;#8217;t found it, please let me know!)&lt;/p&gt;
&lt;p&gt;As we click through to next/previous weeks and it becomes pretty clear that passing the dat=&lt;year&gt;&lt;month&gt;&lt;day&gt; parameter gives you the appropriate listing. Note that they display a month at a time, so all you really have to do is ask for dat=&lt;year&gt;&lt;month&gt;01 every time. We&amp;#8217;re going to build a little scraper that just grabs the current months&amp;#8217; books, but armed with the knowledge of how this works, you should find grabbing 3-4 months worth of books at a time to be no challenge whatsoever (comic book publishers usually solicit about 3 months in advance).&lt;/p&gt;
&lt;p&gt;OK. So now let&amp;#8217;s take a peep at the structure of the document itself. We can do this by just viewing source in a browser. It seems that every comic listed in the release schedule has a link to a full description of the issue, with a cover art previews, a short synopsis, writers/artists listed, etc. And every one of those links seems to have a &lt;span class="caps"&gt;CSS&lt;/span&gt; class of &amp;#8216;contentLink&amp;#8217;. Oh, lucky day.&lt;/p&gt;
&lt;p&gt;This is certainly starting to smell like a job for &lt;a href="http://code.whytheluckystiff.net/hpricot/"&gt;Hpricot&lt;/a&gt;, the super fast (and delightful!) &lt;span class="caps"&gt;HTML&lt;/span&gt; parser for Ruby, written by the enigmatic &lt;a href="http://www.whytheluckystiff.net"&gt;why the lucky stiff&lt;/a&gt;. Gem install that sucker!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gem install hpricot&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&amp;#8217;s fire up IRb and chew on some delicious Ruby syntax:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;require 'hpricot'
require 'open-uri'&lt;/code&gt;

&lt;code&gt;URL_DC = "http://www.dccomics.com/comics/"&lt;/code&gt;

&lt;code&gt;doc = Hpricot(open("#{URL_DC}?dat=#{Time.now.strftime('%y%m01')}"))
books = (doc/"a.contentLink")
books.each { |book| read\_comic(book.innerHTML.strip, 
  "#{URL_DC}#{book.attributes['href']}") }&lt;/code&gt;

&lt;code&gt;def read\_comic(title, url)
  puts "#{title} - #{url}"
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run that, and you&amp;#8217;ll get a list of stuff that looks like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;ALL&lt;/span&gt;-&lt;span class="caps"&gt;NEW&lt;/span&gt; &lt;span class="caps"&gt;ATOM&lt;/span&gt; #12 &amp;#8211; http://www.dccomics.com/comics/?cm=7447&lt;br /&gt;
&lt;span class="caps"&gt;BATMAN&lt;/span&gt;: &lt;span class="caps"&gt;TURNING&lt;/span&gt; &lt;span class="caps"&gt;POINTS&lt;/span&gt; &amp;#8211; http://www.dccomics.com/comics/?cm=7251&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Each output line lists a title with a &lt;span class="caps"&gt;URL&lt;/span&gt;, for each comic solicited in a given month. How does it work? Well, first we open the &lt;span class="caps"&gt;URL&lt;/span&gt; and feed it into Hpricot. Then the line &lt;em&gt;books = (doc/&amp;#8220;a.contentLink&amp;#8221;)&lt;/em&gt; uses a &lt;a href="http://code.whytheluckystiff.net/hpricot/wiki/HpricotCssSearch"&gt;&lt;span class="caps"&gt;CSS&lt;/span&gt; selector&lt;/a&gt; to yank out just the elements that match the selector. We could have also used XPath-style syntax to accomplish the same thing. Anyway, those elements we&amp;#8217;re selecting are all the links to comics being released this month. Hpricot hands us an array of these elements, and then we iterate over them, calling the read_comic function and passing it the title (the innerHTML of the link, stripped of excess whitespace), and the &lt;span class="caps"&gt;URL&lt;/span&gt; (an absolute link to the href attribute of the link).&lt;/p&gt;
&lt;p&gt;Next, let&amp;#8217;s beef up the read_comic function to do something useful. We&amp;#8217;ll have it make another remote connection, this time to the &lt;span class="caps"&gt;URL&lt;/span&gt; specified for the detailed comic description, parse out the talent, description, and some other information about the issue and stuff it into a model object. But first let&amp;#8217;s examine the source of one of those pages. The &lt;a href="http://dccomics.com/comics/?cm= 7173"&gt;Trials of Shazam! #7&lt;/a&gt; should do nicely.&lt;/p&gt;
&lt;p&gt;We note in our examination of the page source that the data we want to scrape is all contained in &lt;span&gt; tags, with different classes, as listed below. Note that this time we&amp;#8217;ve chosen to use XPath-style syntax for the selectors. Note also that the span tag with class=&amp;#8220;display\_copy&amp;#8221; appears twice. The first time, it contains what appears to be the description of the issue, and the second time it lists the publication date. So instead of returning a single element, display\_copy gets an Array of 2 (or possibly more) elements.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def read\_comic(title, url)
  doc = Hpricot(open(url))
  display\_talent = (doc/"span[@class=display\_talent]").innerHTML
  display\_copy = (doc/"span[@class=display\_copy]") # 2 elements
  puts "====="
  puts "title: #{title}"
  puts "talent: #{display\_talent}"
  puts "copy (0): #{display\_copy[0].innerHTML}
  puts "copy (1): #{display\_copy[1].innerHTML}
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we&amp;#8217;re iterating through each book from the remote source, and dumping out it&amp;#8217;s title, the writer and artist responsible for it, a quick synopsis, and some other information (publication date, etc). Alright. If we just had a Comic model in our application, we could be somewhere!&lt;/p&gt;
&lt;p&gt;So let&amp;#8217;s make one. In fact, let&amp;#8217;s do it in Ruby, with ActiveRecord. First the schema:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DROP DATABASE IF EXISTS comics;
CREATE DATABASE comics;
USE comics;&lt;/code&gt;

&lt;code&gt;CREATE TABLE comics (
  id int(11) NOT NULL AUTO\_INCREMENT,
  name VARCHAR(255),
  publisher VARCHAR(255),
  talent VARCHAR(255),
  description TEXT,
  published\_on DATETIME,
  PRIMARY KEY (id)
);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Load this up and then add the following code to the top of your comics scraper. In fact, put it in a file called comics.rb so you can execute it on the command line.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;require 'active\_record'&lt;/code&gt;

&lt;code&gt;ActiveRecord::Base.establish\_connection(
  :adapter  =&amp;gt; 'mysql',
  :host     =&amp;gt; 'localhost',
  :username =&amp;gt; 'root',
  :password =&amp;gt; '',
  :database =&amp;gt; 'comics')&lt;/code&gt;

&lt;code&gt;class Comic &amp;lt; ActiveRecord::Base
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we&amp;#8217;ve established a connection to the database via ActiveRecord and defined a Comic model that inherits from ActiveRecord::Base, thus wrapping our database schema and giving us some handy getters and setters. Our next step will be to trade in the read_comic function in favor of an import class method on the Comic model.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Comic &amp;lt; ActiveRecord::Base
  def self.import(title, url)
    doc = Hpricot(open(url))
    display\_talent = (doc/"span[@class=display\_talent]").innerHTML
    display\_copy = (doc/"span[@class=display\_copy]") # 2 elements&lt;/code&gt;

&lt;code&gt;    comic = Comic.new(:name =&amp;gt; title)
    comic.publisher = "DC"
    comic.talent = display\_talent
    comic.description = display\_copy[0].innerHTML
    comic.published\_on = Date.parse(display\_copy[1].innerHTML.
      sub('on sale', ''))&lt;/code&gt;

&lt;code&gt;    comic
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When Comic.import receives a title and a &lt;span class="caps"&gt;URL&lt;/span&gt; it makes a connection to the &lt;span class="caps"&gt;URL&lt;/span&gt; specified and fires up Hpricot. It uses Hpricot to parse out the information we&amp;#8217;re looking for, and then instantiates an instance of the Comic class. We set the talent, the description (the first of the display\&lt;em&gt;copy spans) and then parse the date out from the second display\&lt;/em&gt;copy span.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ll remove all the output from there and put it in the book loop, since it&amp;#8217;s clearly not the job of the model code to be rendering a view of any sort. Our new book loop will use Comic.import on each element of the books Array, creating the model, saving it, and then printing out some attributes. Here&amp;#8217;s the final code for comics.rb:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;require 'rubygems'
require 'active\_record'
require 'open-uri'
require 'hpricot'&lt;/code&gt;

&lt;code&gt;ActiveRecord::Base.establish\_connection(
  :adapter  =&amp;gt; 'mysql',
  :host     =&amp;gt; 'localhost',
  :username =&amp;gt; 'root',
  :password =&amp;gt; '',
  :database =&amp;gt; 'comics')&lt;/code&gt;

&lt;code&gt;URL_DC = "http://www.dccomics.com/comics/"&lt;/code&gt;

&lt;code&gt;class Comic &amp;lt; ActiveRecord::Base
  def self.import(title, url)
    doc = Hpricot(open(url))
    display\_talent = (doc/"span[@class=display\_talent]").innerHTML
    display\_copy = (doc/"span[@class=display\_copy]") # 2 elements?&lt;/code&gt;

&lt;code&gt;    comic = Comic.new(:name =&amp;gt; title)
    comic.publisher = "DC"
    comic.talent = display\_talent
    comic.description = display_copy[0].innerHTML
    comic.published\_on = Date.parse(display\_copy[1].innerHTML.
      sub('on sale', ''))&lt;/code&gt;

&lt;code&gt;    comic
  end
end&lt;/code&gt;

&lt;code&gt;doc = Hpricot(open("#{URL_DC}?dat=#{Time.now.strftime('%y%m01')}"))
books = (doc/"a.contentLink")
books.each do |book|
  comic = Comic.import(book.innerHTML.strip, 
    "#{URL_DC}#{book.attributes['href']}")
  if comic.save
    puts "====="
    puts "name: #{comic.name}"
    puts "description: #{comic.description}"
    puts "release date: #{comic.published\_on}"
  else
    puts "uh-oh! we should handle errors!"
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here&amp;#8217;s the final result:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;name: &lt;span class="caps"&gt;TRIALS&lt;/span&gt; OF &lt;span class="caps"&gt;SHAZAM&lt;/span&gt;! #7 (OF 12)&lt;br /&gt;
description: Freddy must find Hercules for his next trial, &lt;br /&gt;
which is considerably more difficult than he expected, &lt;br /&gt;
since Herc is behind bars!&lt;br /&gt;
release date: 2007-06-13&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Obviously we can do a lot more with this. We can build a series model, that has_many issues or episodes. We can build a publisher model. We can suck in the images and use RMagick to generate thumbnails. We can discriminate between graphic novels, trade paperbacks, and issues of a standard series book. We can roll this into a Rails application, and allow the results to be browsable, users to add comics to their pull lists, create collections, comment on them, rate them, and so on. Actually, that&amp;#8217;s exactly what I&amp;#8217;m working on for my hobby project (if you&amp;#8217;re interested, email me and I&amp;#8217;ll let you take a look &amp;#8212; I&amp;#8217;m hoping to release it relatively soon-ish).&lt;/p&gt;
&lt;p&gt;To go further with scraping, we&amp;#8217;ll need to pay particular attention to handling errors, because it&amp;#8217;s an inexact science and, since we have no hard format, things are subject to change or break in weird ways. That&amp;#8217;s the obvious downside to scraping. But when you have no other alternative for automating mass import of data like in this scenario, it&amp;#8217;s certainly a good thing to know how to do.&lt;/p&gt;
&lt;p&gt;If you want to learn more, \_why&amp;#8217;s Hpricot site is chock full of useful information, and you may also want to check out &lt;a href="http://scrubyt.org/"&gt;scRUBYt&lt;/a&gt;, which combines Hpricot and &lt;span class="caps"&gt;WWW&lt;/span&gt;::Mechanize into a full-on web scraping &amp;#8220;toolkit&amp;#8221;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Thanks Akismet!</title>
   <link href="http://blog.zerosum.org/2007/6/22/thanks-akismet.html" />
   <published>2007-06-22T00:00:00-04:00</published>
   <updated>2007-06-22T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/6/22/thanks-akismet</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m probably a bit behind the game on this one, but huge props are due to &lt;a href="http://akismet.com/"&gt;Akismet&lt;/a&gt; for making my blog life just a bit more pleasant. Before it was installed last week, I was deleting hoards of comment spam every day. Today, none.&lt;/p&gt;
&lt;p&gt;In other blog-related news, I&amp;#8217;m still planning on moving productions over to Mephisto, but have been hard pressed for time lately. Fortunately (when I get around to it), it has Akismet support baked right in.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="caps"&gt;UPDATE&lt;/span&gt;: finally moved over to a new blogging platform! About time, eh?&lt;/em&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Tumbleranting</title>
   <link href="http://blog.zerosum.org/2007/6/18/tumbleranting.html" />
   <published>2007-06-18T00:00:00-04:00</published>
   <updated>2007-06-18T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/6/18/tumbleranting</id>
   <content type="html">&lt;p&gt;&lt;a href="http://sethgodin.typepad.com/seths_blog/2007/06/letting_off_ste.html"&gt;Seth Godin&lt;/a&gt; is a nicer guy than I am (he&amp;#8217;s probably better dressed, too): I would have ballparked &lt;a href="http://sethgodin.typepad.com/seths_blog/2007/06/letting_off_ste.html"&gt;his quote&lt;/a&gt; a little higher. Explanation: there&amp;#8217;s a &amp;#8220;don&amp;#8217;t waste my time&amp;#8221; fee.&lt;/p&gt;
&lt;p&gt;As a freelancer, this happens to me all the time and it&amp;#8217;s muy frustrating. I like hearing ideas, I like helping you structure your approach, I love developing solutions, applications, tools for you. I don&amp;#8217;t even mind giving estimates and free advice. But in order to do that, you need to tell me what it is you want.&lt;/p&gt;
&lt;p&gt;And no, &amp;#8220;just like digg but with/for xxx&amp;#8221; isn&amp;#8217;t what I&amp;#8217;m talking about :-).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>JRuby / Goldspike / Glassfish Deployment Diary</title>
   <link href="http://blog.zerosum.org/2007/6/11/jruby-goldspike-glassfish-deployment-diary.html" />
   <published>2007-06-11T00:00:00-04:00</published>
   <updated>2007-06-11T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/6/11/jruby-goldspike-glassfish-deployment-diary</id>
   <content type="html">&lt;p&gt;Robert Dempsey has written a pretty solid little &lt;a href="http://www.techcfl.com/blog/?p=116"&gt;tutorial on deploying your first JRuby on Rails app with Glassfish&lt;/a&gt;. It&amp;#8217;s powerful stuff. Go read it now, damnit!&lt;/p&gt;
&lt;p&gt;The process can still be a bit tricky the first time, especially if you have additional gem dependencies, etc. But once you get it running you&amp;#8217;ll be blown away by how simple it is to create a .war and deploy it to any of numerous pre-existing Java application servers (Glassfish).&lt;/p&gt;
&lt;p&gt;I had a few issues initially (particularly with openssl support), so I figured I&amp;#8217;d document them as an addenum to Robert&amp;#8217;s tutorial in case you&amp;#8217;re interested. Read on to see my notes&amp;#8230;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Make sure to set JRUBY_HOME in your environment. It&amp;#8217;s used by Goldspike.&lt;/li&gt;
	&lt;li&gt;If both ruby and jruby are in your path, you can specify the &amp;#8216;version&amp;#8217; of rake to use by doing: &lt;em&gt;jruby -S rake&lt;/em&gt;. This will run the specific command in the JRUBY_HOME/bin directory.&lt;/li&gt;
	&lt;li&gt;Edit the goldspike lib/war_config.rb and change the  line that reference jruby-complete version 0.99 to read:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;add_java_library(maven_library ('org.jruby', 'jruby-complete', '1.0'))&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
	&lt;li&gt;This will look for JRuby 1.0 instead of 0.9.9. As of this writing you&amp;#8217;ll also have to manually retrieve &lt;a href="http://repository.codehaus.org/org/jruby/jruby-complete"&gt;jruby-complete-1.0.jar &lt;/a&gt; as the remote sources don&amp;#8217;t seem to have it yet. Put it in JRUBY_HOME/lib.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;I happen to be using &lt;span class="caps"&gt;SSL&lt;/span&gt; in my app, so I had to gem install it into the JRuby environment using &lt;em&gt;jruby -S gem install jruby-openssl&lt;/em&gt; Make sure the gem ends up in your JRUBY_HOME/lib/ruby/gems hierarchy. Tell goldspike it needs to add this gem with the following line: &lt;em&gt;add_gem(&amp;#8216;jruby-openssl&amp;#8217;)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;If you&amp;#8217;re doing the jruby-openssl thing you&amp;#8217;ll also have to retrieve the latest version of the &lt;a href="http://www.bouncycastle.org/latest_releases.html"&gt;Bouncy Castle Crypto APIs&lt;/a&gt; package for whatever version of Java you&amp;#8217;re using (I&amp;#8217;m on OS X, Java 1.5). Put this in your JRUBY_HOME/lib directory and then add the library to your war_config.rb file:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;add_java_library(maven_library('bouncycastle', 'bcprov-jdk15', '136'))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class="caps"&gt;UPDATES&lt;/span&gt;:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Make sure to copy jdbc_databases.rake from ActiveRecord-&lt;span class="caps"&gt;JDBC&lt;/span&gt; to your lib/tasks directory (for ActiveRecord-related rake tasks). Thanks to Ola Bini for pointing me in the right direction there.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;Include the following in environment.rb:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;if RUBY_PLATFORM =~ /java/
  require 'rubygems'
  RAILS_CONNECTION_ADAPTERS = %w(jdbc)
end
&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>JRuby Reaches 1.0</title>
   <link href="http://blog.zerosum.org/2007/6/10/jruby-reaches-1-0.html" />
   <published>2007-06-10T00:00:00-04:00</published>
   <updated>2007-06-10T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/6/10/jruby-reaches-1-0</id>
   <content type="html">&lt;p&gt;&lt;a href="http://jruby.codehaus.org/"&gt;JRuby 1.0&lt;/a&gt; has been officially released. This is huge news. Complete compatibility with Ruby 1.8 is pretty much a done deal. Rails apps run. You can deploy your Rails apps in Glassfish. I mean, how cool is that?&lt;/p&gt;
&lt;p&gt;You should check out team member &lt;a href="http://headius.blogspot.com/2007/06/jruby-10-released.html"&gt;Charles Nutter&amp;#8217;s blog&lt;/a&gt; for more details. In a nutshell, the future looks like tighter integration with Java as an application platform, and a major focus on optimizing performance. Also a lot of interest in Ruby 1.9/2.0. If you attended Railsconf this year, you most likely got pretty excited about JRuby, and for good reason.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;ve never tried it out before, &lt;a href="http://www.techcfl.com/blog/?p=109"&gt;Atlantic Dominion Solutions&lt;/a&gt; has put together a great tutorial on getting started with JRuby on OS X. Or, even easier, go get yourself a copy of &lt;a href="http://www.netbeans.org/community/releases/60/index.html"&gt;NetBeans 6.0 M9&lt;/a&gt;, which comes bundled with JRuby as the default interpreter for in-&lt;span class="caps"&gt;IDE&lt;/span&gt; development.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>NHRuby Meeting Tuesday 06.12</title>
   <link href="http://blog.zerosum.org/2007/6/8/nhruby-meeting-tuesday-06-12.html" />
   <published>2007-06-08T00:00:00-04:00</published>
   <updated>2007-06-08T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/6/8/nhruby-meeting-tuesday-06-12</id>
   <content type="html">&lt;p&gt;Usually the NHRuby meets are scheduled for the third Tuesday of the month, but we had to change it up this time due to some schedule conflicts.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll be speaking about integrating a Flash widget with Rails-based RESTful web services and also giving a brief overview of how to contribute to Rails and other open source projects (I guess you could say Josh Susser&amp;#8217;s talk at Railsconf inspired me). &lt;a href="http://blog.zenlinux.com/"&gt;Scott&lt;/a&gt; will be doing an overview of the tabnav plugin and&amp;#8230; something else, too.&lt;/p&gt;
&lt;p&gt;More information and directions can be found at the &lt;a href="http://wiki.nhruby.org/index.php/Upcoming_meetings"&gt;NHRuby Wiki&lt;/a&gt;. Also, many thanks to our new host/sponsor for the meetings, &lt;a href="http://www.rmcres.com/"&gt;&lt;span class="caps"&gt;RMC&lt;/span&gt; Research&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>LOLCODE</title>
   <link href="http://blog.zerosum.org/2007/6/6/lolcode.html" />
   <published>2007-06-06T00:00:00-04:00</published>
   <updated>2007-06-06T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/6/6/lolcode</id>
   <content type="html">[3:44pm] strager: &lt;span class="caps"&gt;BUKKIT&lt;/span&gt; is the array type.
[3:44pm] zapnap: O &lt;span class="caps"&gt;RLY&lt;/span&gt;?</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>has_much :confusion, :about =&gt; "string #{interpolation}"</title>
   <link href="http://blog.zerosum.org/2007/6/5/has_much-confusion-about-string-interpolation.html" />
   <published>2007-06-05T00:00:00-04:00</published>
   <updated>2007-06-05T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/6/5/has_much-confusion-about-string-interpolation</id>
   <content type="html">&lt;p&gt;No matter how flexible ActiveRecord&amp;#8217;s associations become, there&amp;#8217;s always going to be a time when you want to override it&amp;#8217;s baked-in smarts with your own custom &lt;span class="caps"&gt;SQL&lt;/span&gt; query. Fortunately, we can do just that with the :finder\_sql option. Use it to manually specify the association that should be returned.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s one gotcha to be aware of though: if you need to do any variable interpolation in the string (and you most likely will), make sure to use single quotes instead of the usual doubles:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;has_many :transfers, :finder_sql =&amp;gt; 
  'SELECT * FROM transfers ' +
  'WHERE sender_id = #{id} or receiver_id = #{id}'&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you use double quotes, the string interpolation happens immediately (when the class is first loaded), thus obtaining the object ID of the class in memory. Using single quotes, the interpolation occurs within the context of your object instance, which is what you&amp;#8217;re expecting.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Caught In The Act</title>
   <link href="http://blog.zerosum.org/2007/5/31/caught-in-the-act.html" />
   <published>2007-05-31T00:00:00-04:00</published>
   <updated>2007-05-31T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/5/31/caught-in-the-act</id>
   <content type="html">&lt;p&gt;Wow, &lt;a href="http://maps.google.com/help/maps/streetview/index.html"&gt;Google Street View&lt;/a&gt; is totally great. And, as expected, some &lt;a href="http://mashable.com/2007/05/31/top-15-google-street-view-sightings/"&gt;funny shit&lt;/a&gt; gets frozen in time at street level. Google is watching! Be cautious where you go, what you do! Try to remain calm, don&amp;#8217;t &lt;a href="http://maps.google.com/maps?f=q&amp;hl=en&amp;q=San+Francisco,+San+Francisco,+California,+United+States&amp;sll=40.714997,-74.006653&amp;sspn=0.617251,1.035461&amp;ie=UTF8&amp;cd=1&amp;om=1&amp;layer=c&amp;cbll=37.816636,-122.371755&amp;cbp=2,488.471398279527,0.577637392429255,3&amp;ll=37.82843,-122.369843&amp;spn=0.023389,0.054245&amp;z=15"&gt;lose your head&lt;/a&gt; over it.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>ActiveRecord Delegation Pitfalls</title>
   <link href="http://blog.zerosum.org/2007/5/30/activerecord-delegation-pitfalls.html" />
   <published>2007-05-30T00:00:00-04:00</published>
   <updated>2007-05-30T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/5/30/activerecord-delegation-pitfalls</id>
   <content type="html">&lt;p&gt;Delegation is a powerful concept. And it&amp;#8217;s a useful Ruby mixin, too. You can use the delegation mixin to easily expose related objects&amp;#8217; methods as your own, which makes for much cleaner code than defining those methods by hand. However, there are some pitfalls to be aware of when dealing with delegation and the ActiveRecord lifecycle.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s a simple example of delegation in action:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class User &amp;lt; ActiveRecord::Base
  has_one :homepage, :class_name =&amp;gt; "Article"
  delegate :url, :to =&amp;gt; :homepage
end&lt;/code&gt;

&lt;code&gt;my_user.url =&amp;gt; url of the home page article for this user&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yes, we could just call my_user.homepage.url here too. But there are definitely some situations where you&amp;#8217;d prefer not to do this. I won&amp;#8217;t attempt to relate my present situation to yours, as it&amp;#8217;s outside the scope of this discussion. Anyway, the point is that delegation can be used to make your life easier.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s where we get into trouble:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;new_user = User.new
new_user.url&lt;/code&gt;

&lt;code&gt;NoMethodError: You have a nil object when you didn't expect it!
The error occurred while evaluating nil.url&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;O &lt;span class="caps"&gt;NOES&lt;/span&gt;! What happened?&lt;/p&gt;
&lt;p&gt;In a nutshell, when we use it in our model, the delegate class method defines a bunch of new instance methods on our User object. These methods simply forward their queries onto the target (:to) object. If the target object, at the present stage in the AR model lifecycle, happens to be nil, then we&amp;#8217;re trying to call a method on nil. The nil object doesn&amp;#8217;t have a url method, so we&amp;#8217;re toast.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def #{method}(*args, &amp;amp;block)
  #{to}.__send__(#{method.inspect}, *args, &amp;amp;block)
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;How can we get around this? Well, court3nay opened a &lt;a href="http://dev.rubyonrails.org/ticket/4134"&gt;ticket&lt;/a&gt; to address this a while back. It was recently closed due to inactivity. I just reopened it, and added a small patch. Here&amp;#8217;s the difference in the way the mixin creates the delegated methods:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-  #{to}.__send__(#{method.inspect}, *args, &amp;amp;block)
+  #{to}.__send__("nil?") ? nil : #{to}.__send__(#{method.inspect}, *args, &amp;amp;block)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty simple really. We just test the delegation target to see if it&amp;#8217;s nil first. If it is, we return nil instead of trying to send it a message. Otherwise, we call the method on the target object and let the receiver worry about it.&lt;/p&gt;
&lt;p&gt;Huzzah, we&amp;#8217;ve successfully delegated the task of dealing with nil delegation targets! Way special, eh?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Sometimes It's The Little Things, pt 2</title>
   <link href="http://blog.zerosum.org/2007/5/26/sometimes-it-s-the-little-things-pt-2.html" />
   <published>2007-05-26T00:00:00-04:00</published>
   <updated>2007-05-26T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/5/26/sometimes-it-s-the-little-things-pt-2</id>
   <content type="html">&lt;p&gt;So my first patch to Rails core was accepted yesterday. It&amp;#8217;s a &lt;a href="http://dev.rubyonrails.org/ticket/8120"&gt;tiny, tiny patch&lt;/a&gt;. All it does is add a :method parameter to the auto_complete_field helper so you can do &lt;a href="http://blog.zerosum.org/?q=node/47"&gt;RESTful autocompletion&lt;/a&gt; (the filter query should be submitted with a &lt;span class="caps"&gt;GET&lt;/span&gt;, not a &lt;span class="caps"&gt;POST&lt;/span&gt;, if you want to follow the &lt;span class="caps"&gt;REST&lt;/span&gt; conventions).&lt;/p&gt;
&lt;p&gt;No big deal really, but it feels good to finally be able to &amp;#8220;give back&amp;#8221; to the community in a way other than blogging and &lt;span class="caps"&gt;IRC&lt;/span&gt; help. You know, with like, actual code that benefits people other than just me. I&amp;#8217;ve contributed to a handful of Java and &lt;span class="caps"&gt;PHP&lt;/span&gt;-based &lt;span class="caps"&gt;OSS&lt;/span&gt; projects over the years, but this is officially my first contribution to a Ruby-based project, and that certainly feels like a step in the right direction.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Railsconf 2007 FTW</title>
   <link href="http://blog.zerosum.org/2007/5/21/railsconf-2007-ftw.html" />
   <published>2007-05-21T00:00:00-04:00</published>
   <updated>2007-05-21T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/5/21/railsconf-2007-ftw</id>
   <content type="html">&lt;p&gt;Had a great time at &lt;a href="http://www.railsconf.com"&gt;Railsconf 2007&lt;/a&gt;! Just got back. A little jetlagged, and in need of (another) nap. In summary: lots of good presentations, &lt;a href="http://www.pubcrawler.com/Template/searchwc.cfm/flat/zipcode=97201/distance=25/title=Portland,%20Oregon"&gt;superb microbrews&lt;/a&gt;, a hilarious &lt;a href="http://www.zefrank.com/"&gt;zefrank&lt;/a&gt; performance, and a number of lurking lolcats.&lt;/p&gt;
&lt;p&gt;Highlights for me included DHH&amp;#8217;s keynote, &lt;a href="http://www.therailsway.com"&gt;the Rails way&lt;/a&gt; &amp;#8216;live&amp;#8217; performance by Jamis and Koz (although I have to politely disagree with them on the need for private ActiveRecord attributes), Ezra&amp;#8217;s &lt;a href="http://brainspl.at/articles/2007/05/20/my-xen-and-the-art-of-rails-deployment-talk-slides"&gt;deployment and scaling session&lt;/a&gt;, and the homesteading talk by &lt;a href="http://www.matthewbass.com/blog/"&gt;Matthew Bass&lt;/a&gt;. Thanks to everyone who helped make it happen.&lt;/p&gt;
&lt;p&gt;Also got to meet some fellow &lt;span class="caps"&gt;IRC&lt;/span&gt; peeps in person. Now ur tru idinty is nown to me, bewar!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Oregon</title>
   <link href="http://blog.zerosum.org/2007/5/16/oregon.html" />
   <published>2007-05-16T00:00:00-04:00</published>
   <updated>2007-05-16T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/5/16/oregon</id>
   <content type="html">&lt;p&gt;So here I am in sunny Oregon. Around 1PM I hop on a train headed to Portland for &lt;a href="http://www.railsconf.com"&gt;RailsConf&lt;/a&gt; 07. Came out a few days early to catch up with my good buddy &lt;a href="http://www.tyrauber.com"&gt;Ty&lt;/a&gt; in Eugene and work on the startup idea we&amp;#8217;ve been banging around. And do some hiking, drinking, and dissecting of Heroes too, of course.&lt;/p&gt;
&lt;p&gt;I kind of love being out here and yet still having my internal clock set to east coast time. I wake up &amp;#8220;early&amp;#8221; for a change, and bang out a nasty chunk of work before anyone else here is even awake yet. Otoh, I feel like an old man when I begin to falter around 11PM. Heh.&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;#8217;m looking forward to the conference. I&amp;#8217;ll be attending the tutorials day tomorrow, specifically the scaling session with Joyent&amp;#8217;s Jason Hoffman as well as David Black&amp;#8217;s &amp;#8216;Routing Roundup&amp;#8217;. If you see me, say hi.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Deconstructing date_select</title>
   <link href="http://blog.zerosum.org/2007/5/9/deconstructing-date_select.html" />
   <published>2007-05-09T00:00:00-04:00</published>
   <updated>2007-05-09T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/5/9/deconstructing-date_select</id>
   <content type="html">&lt;p&gt;date_select and it&amp;#8217;s friend datetime_select are handy little helpers for rendering date selection widgets in your form, but what they hand back to your controller is a little bit unintuitive. If you&amp;#8217;re just going to go ahead and use update_attributes on your model, then ActiveRecord magically takes care of converting these to an appropriate Date or Time object for you. However, if you&amp;#8217;re not doing that, you&amp;#8217;ll find yourself staring at keys in your hash named odd things like &amp;#8220;attribute(1i)&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s a handy little helper method, in case you ever need to manually reconstruct a Date object from the params:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Reconstruct a date object from date_select helper form params
def build_date_from_params(field_name, params)
  Date.new(params["#{field_name.to_s}(1i)"].to_i, 
           params["#{field_name.to_s}(2i)"].to_i, 
           params["#{field_name.to_s}(3i)"].to_i)
end&lt;/code&gt;

&lt;code&gt;date = build_date_from_params(:published_at, params[:article])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Put this in your ApplicationController so inherited controller classes can access it, or (better yet) put it in a suite of helper methods to mix in to application.rb. Not exactly brain surgery here, but I&amp;#8217;m a little surprised that there isn&amp;#8217;t something already baked into the helpers to do this.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>MyConfPlan: Check Me Out</title>
   <link href="http://blog.zerosum.org/2007/4/27/myconfplan-check-me-out.html" />
   <published>2007-04-27T00:00:00-04:00</published>
   <updated>2007-04-27T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/4/27/myconfplan-check-me-out</id>
   <content type="html">&lt;p&gt;&lt;a href="http://www.drnicwilliams.com/"&gt;Dr Nic Williams&lt;/a&gt; wrote a nice little app to allow folks to plot out the sessions they&amp;#8217;ll be attending at &lt;a href="http://www.railsconf.com"&gt;Railsconf&lt;/a&gt; (or any conference, for that matter) and share them with others. In case you&amp;#8217;re curious, check out &lt;a href="http://www.myconfplan.com/conferences/RailsConf2007/users/zapnap"&gt;my tentative session list&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some of those decisions are tough ones! In particular, I&amp;#8217;d like to see both Nutter&amp;#8217;s JRuby talk as well as Dan Webb&amp;#8217;s javascript-fu presentation. I&amp;#8217;d also like to attend both Matthew Bass&amp;#8217; homesteading talk as well as Brian Leonard&amp;#8217;s Tooling/NetBeans session. Sigh, decisions decisions.&lt;/p&gt;
&lt;p&gt;Also of note: Dr Nic built MyConfPlan in &lt;a href="http://hobocentral.net/"&gt;Hobo&lt;/a&gt;, which seems to have come a long way since I last checked it out. Very cool stuff.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>REST vs AutoComplete</title>
   <link href="http://blog.zerosum.org/2007/4/18/rest-vs-autocomplete.html" />
   <published>2007-04-18T00:00:00-04:00</published>
   <updated>2007-04-18T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/4/18/rest-vs-autocomplete</id>
   <content type="html">&lt;p&gt;After struggling with it probably a little bit more than I should have, I&amp;#8217;ve totally come around to the &lt;span class="caps"&gt;REST&lt;/span&gt; way of looking at things. It seems clean and nice, and I&amp;#8217;m 100% behind it. That said, I&amp;#8217;ve found that once you adopt the mentality, things that don&amp;#8217;t gel with it start to stick out like the guy in the fur coat at the &lt;span class="caps"&gt;PETA&lt;/span&gt; meeting.&lt;/p&gt;
&lt;p&gt;Case in point: the ever-popular Rails auto_complete_field helper. To back up my accusation here, let&amp;#8217;s walk through an example scenario with a &lt;span class="caps"&gt;REST&lt;/span&gt; app, and examine the issues that arise&amp;#8230;&lt;/p&gt;
&lt;p&gt;Imagine a really simple web application which consists of a collection of Articles. The only user interaction is that guests can comment on articles and tag them with keywords. So in a RESTful world, we have an Articles resource, and a Tags resource. Tags are also nested on Articles such that when you ask for /articles/:article_id/tags you&amp;#8217;re asking for the subset of tags which have been applied to article_id. We might present these as a tab you can click on when viewing an article resource in a browser.&lt;/p&gt;
&lt;p&gt;Now let&amp;#8217;s say that there&amp;#8217;s a form somewhere (maybe the #new action on an ArticleCommentsController), which can  be used to apply new tags to a given article. There&amp;#8217;s an auto_complete_field in that form, that will suggest tags to apply to an article, based on the tags that have already been applied. Dumb example, I know, but hear me out.&lt;/p&gt;
&lt;p&gt;So, given this scenario, it would make sense to point our auto_complete_field helper at article_tags_path(article_id). This is about as RESTful as it gets &amp;#8212; we&amp;#8217;ve become a client of our own &lt;span class="caps"&gt;API&lt;/span&gt;. Nice! Our #index action on ArticleTagsController, in a perfect world, would do a couple things above and beyond just displaying the pretty &lt;span class="caps"&gt;HTML&lt;/span&gt; list of tags on the article:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;It would have a respond_to block.&lt;/strong&gt; if a browser client is asking for &lt;span class="caps"&gt;XHTML&lt;/span&gt;, we probably want to render a nice paginated view of the relevant tags, ordered by weight, with a nice layout. On the other hand, if we&amp;#8217;re asking for &lt;span class="caps"&gt;XML&lt;/span&gt; or &lt;span class="caps"&gt;JSON&lt;/span&gt;, it just returns no-frills data in the appropriate format.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;it would optionally check for a filter query string.&lt;/strong&gt; perhaps we set params[:filter] = :attribute_name and then make the actual string filter value (the thing we&amp;#8217;re trying to help auto-complete) available via params[:attribute_name]. in the case of our tags example, we&amp;#8217;d end up with a params hash that has filter=name and name=zer (or some other text string). If a filter parameter is found, we&amp;#8217;d filter the results by the pattern specified. This could all be wrapped up in a nice little helper.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This proposal raises a couple issues. First, the auto_complete_field helper as it exists today expects us to return some &lt;span class="caps"&gt;HTML&lt;/span&gt; from the &lt;span class="caps"&gt;AJAX&lt;/span&gt; call that we can plug into an appropriately named &lt;span class="caps"&gt;DIV&lt;/span&gt;. This is simple and works well, but if we&amp;#8217;re really consuming our own web service, we should probably be talking to it via &lt;span class="caps"&gt;JSON&lt;/span&gt; or &lt;span class="caps"&gt;XML&lt;/span&gt; and have a JavaScript handler to process the results, converting them into list format or whatever it is that we desire. But I have to admit that this convenient hack works nicely.&lt;/p&gt;
&lt;p&gt;More importantly, if the auto-complete filter is being applied to the collection of resources, that means it maps to the #index action by way of a &lt;span class="caps"&gt;GET&lt;/span&gt; request. So our parameters end up encoded in the &lt;span class="caps"&gt;URL&lt;/span&gt; with a query string like ?filter=name&amp;amp;name=zer. Obviously, &lt;span class="caps"&gt;GET&lt;/span&gt; params are a little more limiting than &lt;span class="caps"&gt;POST&lt;/span&gt; params in terms of length and (perceived) security. But for simple filter strings that take a short sequence of characters, I don&amp;#8217;t see this as being an issue. And this is always the case when doing an auto-complete, as far as I can figure.&lt;/p&gt;
&lt;p&gt;Note that the auto_complete_field JavaScript helper doesn&amp;#8217;t actually allow you to specify an &lt;span class="caps"&gt;HTTP&lt;/span&gt; verb other than &lt;span class="caps"&gt;POST&lt;/span&gt;, although that&amp;#8217;s easy enough to change. Surely the core team would accept the one-line fix required to support a :method =&amp;gt; :get option if it&amp;#8217;s the &amp;#8220;right thing to do&amp;#8221;. The real problem is more of a philosophical one: are we, as a community, really going to embrace &lt;span class="caps"&gt;REST&lt;/span&gt; 100% or is it acceptable to add small bits of cruftiness in places where it seems inconvenient?&lt;/p&gt;
&lt;p&gt;A perfectly legitimate half-way solution is to define a standard #autocomplete action for any resource you want to use in this manner. The advantage to this is that you can easily use a &lt;span class="caps"&gt;POST&lt;/span&gt; against a custom :collection method on the resource. That way, we continue to work inside the existing box of conventions. But I ask you, is that really RESTful?! What do you think?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>NH Ruby UG Lightening Talks Tonight!</title>
   <link href="http://blog.zerosum.org/2007/4/17/nh-ruby-ug-lightening-talks-tonight.html" />
   <published>2007-04-17T00:00:00-04:00</published>
   <updated>2007-04-17T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/4/17/nh-ruby-ug-lightening-talks-tonight</id>
   <content type="html">&lt;p&gt;Join us tonight at the Portsmouth Public Library for a bunch of lightening talks on Ruby-related subjects. I&amp;#8217;ll be speaking on &lt;span class="caps"&gt;REST&lt;/span&gt;, Rake, and RMagick (if I can manage to put together a preso and demo app in time). &lt;a href="http://blog.zenlinux.com"&gt;Scott&lt;/a&gt; will be presenting a demo of his Rails-based ProgressPuppy task manager. And there will be other stuff, too.&lt;/p&gt;
&lt;p&gt;Note that we&amp;#8217;re still doing the meeting, despite aftereffects of the nasty coastal flooding. Hardcore, eh?  As always, more information (including directions) can be found at the &lt;a href="http://wiki.nhruby.org"&gt;NHRuby Wiki&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>RailRoad Class Visualization</title>
   <link href="http://blog.zerosum.org/2007/4/10/railroad-class-visualization.html" />
   <published>2007-04-10T00:00:00-04:00</published>
   <updated>2007-04-10T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/4/10/railroad-class-visualization</id>
   <content type="html">&lt;p&gt;Just saw &lt;a href="http://www.infoq.com/news/2007/04/rails-diagrams-railroad"&gt;this InfoQ article&lt;/a&gt; about RailRoad and had to check it out. Gotta say, this is by far the best class visualization tool for RoR I&amp;#8217;ve seen yet. Set your options, generate those &lt;span class="caps"&gt;DOT&lt;/span&gt; files, and then run them through &lt;a href="http://www.graphviz.org/"&gt;GraphViz&lt;/a&gt; to export your image format of choice. Couldn&amp;#8217;t be easier.&lt;/p&gt;
&lt;p&gt;Check out some of the examples on the &lt;a href="
http://railroad.rubyforge.org/"&gt;RailRoad RubyForge site&lt;/a&gt;, including the diagrams of the popular Depot example app and the much more complex Typo blog package. The latter is a good illustration of why the &lt;em&gt;brief&lt;/em&gt; option is provided, heh. If you&amp;#8217;re in the &lt;span class="caps"&gt;UML&lt;/span&gt; camp, you might be a little disappointed as the diagrams it produces are closer to &lt;a href="http://www.bon-method.com"&gt;&lt;span class="caps"&gt;BON&lt;/span&gt;&lt;/a&gt;, but personally I think they&amp;#8217;re very straightforward and natural.&lt;/p&gt;
&lt;p&gt;Whatever your modeling language preference is, I think we can agree that tools like this go a long way towards legitimizing Rails use in large multi-person projects and are, well, just plain helpful. Big thumbs up.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Paginating Associations</title>
   <link href="http://blog.zerosum.org/2007/4/10/paginating-associations.html" />
   <published>2007-04-10T00:00:00-04:00</published>
   <updated>2007-04-10T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/4/10/paginating-associations</id>
   <content type="html">&lt;p&gt;It&amp;#8217;s no real secret that the default Rails pagination helpers are kind of awful. Sure, you can use them, but I wouldn&amp;#8217;t recommend it if you expect to scale. Instead, go snag yourself the wonderful &lt;a href="http://cardboardrocket.com/pages/paginating_find"&gt;paginating_find&lt;/a&gt; plugin. And then, if you&amp;#8217;re going to be using them with your model associations, whip up an association extension like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module PaginationExtension
  def paginate(current = 1, size = 10, options = {})
    options[:page] = {:current =&amp;gt; current, :size =&amp;gt; size}
    find(:all, options)
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now just extend the has_many association on your City class and you can call &lt;em&gt;city.bars.paginate(2)&lt;/em&gt; to get the second 10-element page of bars associated with your city.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class City &amp;lt; ActiveRecord::Base
  has_many :bars, :extend =&amp;gt; PaginationExtension
end&lt;/code&gt;

&lt;code&gt;city.bars.paginate(2)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The good bars are all on the first page though, so consider yourself warned.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rake: Ant Be Gone!</title>
   <link href="http://blog.zerosum.org/2007/4/2/rake-ant-be-gone.html" />
   <published>2007-04-02T00:00:00-04:00</published>
   <updated>2007-04-02T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/4/2/rake-ant-be-gone</id>
   <content type="html">&lt;p&gt;I spent the better part of my morning today writing some code to do sample data generation within the framework we&amp;#8217;re building. I&amp;#8217;d originally packaged it as a standalone utility class to be run with the script/runner facility until I realized that it was a perfect candidate for a custom Rake task. And a perfect topic for a blog entry &amp;#8212; two for the win!&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;ve never written a Rake task before and are a Ruby pseudo-noob, fear not. If you&amp;#8217;ve written Ant or Make scripts before, and have the requisite passing familiarity with Ruby, it&amp;#8217;ll be old hat. Of course, the big win with Rake is that you get to write your tasks in Ruby. Sweet, sweet Ruby. No crufty &lt;span class="caps"&gt;XML&lt;/span&gt; here.&lt;/p&gt;
&lt;p&gt;What follows is pretty minimalist, but I wanted to record it for posterity. Also, many of the tutorials I looked at didn&amp;#8217;t deal with handling parameters, so I figured it might be useful to someone else out there&amp;#8230;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;namespace :foo do
  desc "Generate sample data for the app"
  task :sample_data =&amp;gt; [:environment] do |t|
    require 'db/script/sample_data.rb'&lt;/code&gt;

&lt;code&gt;    num_users = ENV.include?('NUM_USERS') ? ENV['NUM_USERS'] : 5
    SampleData.generate(num_users.to_i)
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What we&amp;#8217;re doing here is defining a task named &lt;em&gt;sample_data&lt;/em&gt; within the &lt;em&gt;foo&lt;/em&gt; namespace. We declare a dependency on the Rails :environment, which is a little gift from the Rails team allowing you to write code in your tasks that lives within your app&amp;#8217;s pre-existing environment. The &lt;em&gt;desc&lt;/em&gt; line serves as a comment about what the task does, and will appear alongside the task name when you query it with the &amp;#8212;tasks parameter.&lt;/p&gt;
&lt;p&gt;Within the body of the task we simply require the script we&amp;#8217;re going to run, in this case my virtually unmodified utility class, and then we check to see if a parameter named NUM_USERS was passed in. If it was, we use that value to determine the number of users to create. If it wasn&amp;#8217;t, we default to 5.&lt;/p&gt;
&lt;p&gt;Because Rails is smart, and talented in the mystical arts, it auto-loads any files in &lt;em&gt;lib/tasks&lt;/em&gt; that have a &lt;em&gt;.rake&lt;/em&gt; extension. So just plop this file in that directory and you can then check the available Rake tasks from the top level of your project. You should see our new task definition there:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ rake --tasks | grep sample
rake foo:sample_data              # Generate sample data for the app&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rockin. So let&amp;#8217;s run it. As you can see from the output below, it calls the utility calss, creating 10 sample users (and a bunch of other stuff I&amp;#8217;ve excluded). Couldn&amp;#8217;t be easier.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake foo:sample_data NUM_USERS=10
SampleData: generating 10 users, blah blah blah...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I hope this has been helpful, and if you&amp;#8217;re looking for more information, make sure to check out &lt;a href="http://www.martinfowler.com/articles/rake.html"&gt;Martin Fowler&amp;#8217;s seemingly definitive reference&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Sometimes It's The Little Things...</title>
   <link href="http://blog.zerosum.org/2007/3/29/sometimes-it-s-the-little-things.html" />
   <published>2007-03-29T00:00:00-04:00</published>
   <updated>2007-03-29T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/3/29/sometimes-it-s-the-little-things</id>
   <content type="html">&lt;p&gt;With this latest RoR project, we decided for the first time to take a RESTful approach. It&amp;#8217;s taken me much longer than it should have to come to terms with what that actually meant, but after suffering through the change of mindset, I really do have to say that it feels &lt;em&gt;right&lt;/em&gt;. I&amp;#8217;m down, you&amp;#8217;ve won me over.&lt;/p&gt;
&lt;p&gt;That said, there are always little implementation details that annoy the hell out of you. Little, trivial, stupid things. Things that you know you shouldn&amp;#8217;t waste precious breath complaining about, things that you annoy your friends about until they ignore you. Things like the use of the damn semi-colon to delimit custom actions for resources in a &lt;span class="caps"&gt;URI&lt;/span&gt;, instead of our old friend the slash.&lt;/p&gt;
&lt;p&gt;And then came &lt;a href="http://dev.rubyonrails.org/changeset/6485"&gt;Changeset 6485&lt;/a&gt;, which made everything once again &lt;a href="http://ryandaigle.com/articles/2007/3/29/what-s-new-in-edge-rails-restful-routes-get-a-new-custom-delimiter"&gt;right with the world&lt;/a&gt;. Thank gawd that&amp;#8217;s over. Now I can get back to being productive :-).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>NH Ruby UG Meeting.003 Tonight!</title>
   <link href="http://blog.zerosum.org/2007/3/20/nh-ruby-ug-meeting-003-tonight.html" />
   <published>2007-03-20T00:00:00-04:00</published>
   <updated>2007-03-20T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/3/20/nh-ruby-ug-meeting-003-tonight</id>
   <content type="html">&lt;p&gt;If you&amp;#8217;re in the seacoast New Hampshire area, don&amp;#8217;t forget to attend tonight&amp;#8217;s &lt;a href="http://wiki.nhruby.org/index.php/Upcoming_meetings"&gt;NH Ruby User Group&lt;/a&gt; meeting. Click on the link for directions.&lt;/p&gt;
&lt;p&gt;Brian DeLacey will be speaking on &lt;em&gt;Security and Cryptography in Ruby on Rails&lt;/em&gt;, and there will be some free book giveaways from O Reilly.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>AR Model Initialization Notes</title>
   <link href="http://blog.zerosum.org/2007/3/16/ar-model-initialization-notes.html" />
   <published>2007-03-16T00:00:00-04:00</published>
   <updated>2007-03-16T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/3/16/ar-model-initialization-notes</id>
   <content type="html">&lt;p&gt;If you&amp;#8217;re new to Rails but not to Ruby, you might be surprised to learn that Rails doesn&amp;#8217;t use the standard Ruby &lt;em&gt;initialize()&lt;/em&gt; method when Model.new is invoked or when a model instance is returned from a find.&lt;/p&gt;
&lt;p&gt;If you need to add some initialization code to an ActiveRecord model, use the &lt;em&gt;after_initialze&lt;/em&gt; callback instead:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def after_initialize
  @thing = SomethingElse.new(self)
  @foo = 'bar'
end
&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>March Reading List</title>
   <link href="http://blog.zerosum.org/2007/3/12/march-reading-list.html" />
   <published>2007-03-12T00:00:00-04:00</published>
   <updated>2007-03-12T00:00:00-04:00</updated>
   <id>http://blog.zerosum.org/2007/3/12/march-reading-list</id>
   <content type="html">&lt;p&gt;We&amp;#8217;ve been hard at work lately, so blog updates have been a little more infrequent than I&amp;#8217;d like. But in the meantime, I thought I&amp;#8217;d post some books I&amp;#8217;ve been reading. All come highly recommended.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.amazon.com/Ruby-Rails-Techniques-Developers/dp/1932394699/ref=sr_1_1/104-1846407-8777520?ie=UTF8&amp;s=books&amp;qid=1173731744&amp;sr=8-1"&gt;David A Black&amp;#8217;s Ruby For Rails&lt;/a&gt; &amp;#8211; Essential Ruby/Rails reading. How did I get this far without it?&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.amazon.com/Founders-Work-Stories-Startups-Early/dp/1590597141/ref=pd_bbs_sr_1/104-1846407-8777520?ie=UTF8&amp;s=books&amp;qid=1173731948&amp;sr=8-1"&gt;Founders At Work&lt;/a&gt; &amp;#8211; Working on a startup? You should be.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.amazon.com/Small-New-Big-Remarkable-Business/dp/1591841267/ref=pd_bbs_sr_1/104-1846407-8777520?ie=UTF8&amp;s=books&amp;qid=1173732118&amp;sr=1-1"&gt;Seth Godin&amp;#8217;s Small Is the New Big&lt;/a&gt; &amp;#8211; Learn how to be remarkable. Or at least, how to market your remarkability.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.amazon.com/Y-Last-Vol-Kimono-Dragons/dp/1401210104/ref=pd_bbs_sr_2/104-1846407-8777520?ie=UTF8&amp;s=books&amp;qid=1173732200&amp;sr=1-2"&gt;Y the Last Man&lt;/a&gt; &amp;#8211; Damn, Brian K Vaughn rules. Plus, he likes The Eels. And he&amp;#8217;s writing for Lost now, too. Read this, even if you don&amp;#8217;t read comics.&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Tweaking The Rails Logger</title>
   <link href="http://blog.zerosum.org/2007/3/5/tweaking-the-rails-logger.html" />
   <published>2007-03-05T00:00:00-05:00</published>
   <updated>2007-03-05T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/3/5/tweaking-the-rails-logger</id>
   <content type="html">&lt;p&gt;The &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/classes/Logger.html"&gt;Ruby&lt;/a&gt; &lt;a href="http://rdoc.caboo.se/doc/classes/Logger.html"&gt;Logger&lt;/a&gt; is a simple but pretty flexible tool &amp;#8212; hopefully you&amp;#8217;re already using it. If not, you should be. The default logger message format is pretty barebones though, so I thought I&amp;#8217;d take a few minutes to talk about how to make it more useful by monkey patching format_message.&lt;/p&gt;
&lt;p&gt;First, make sure to check out TopFunky&amp;#8217;s &lt;a href="http://nubyonrails.com/articles/2007/01/03/a-hodel-3000-compliant-logger-for-the-rest-of-us"&gt;&amp;#8216;Hodel 3000 compliant logger&amp;#8217;&lt;/a&gt; article, posted a couple months ago. Geoffrey&amp;#8217;s syslog-friendly modification works great when running in production mode. Customized log messages are just as important in the development environment, where we&amp;#8217;ve made our own simple modifications to include the name and line number of the file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Logger
  def format_message(severity, timestamp, msg, progname)
    "#{Kernel.caller[2]}: #{severity.upcase}: #{progname.gsub(/\n/, '').lstrip}\n"
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This little snippet is especially handy if you&amp;#8217;re using an &lt;span class="caps"&gt;IDE&lt;/span&gt; like IntelliJ that&amp;#8217;s smart enough to hyperlink the file path. Got an error being logged in users_controller.rb on line 91? Click on the hyperlink and you&amp;#8217;re there.&lt;/p&gt;
&lt;p&gt;It works by accessing the execution stack Array returned by Kernel.caller. caller&lt;sup class="footnote" id="fnr0"&gt;&lt;a href="#fn0"&gt;0&lt;/a&gt;&lt;/sup&gt; will refer to the line in Logger#add where format_message is called. caller&lt;sup class="footnote" id="fnr1"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt; is most likely going to point to one of the Logger#&lt;severity&gt; methods, one of [ debug, info, warn, error, fatal ]. This is the next level down in the stack, where the add method was called from. In most &amp;#8220;application-level&amp;#8221; code (code we actually write in our application, exterior to the benchmarking messages and such that Rails gives us for free), caller&lt;sup class="footnote" id="fnr2"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt; is going to be something in our application code itself, some place that we called logger.info, or logger.error, or whatever, from.&lt;/p&gt;
&lt;p&gt;To get this installed in our environment we create a file development_logger.rb, containing the source above. Then, in development.rb (or the initializer block of environment.rb):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;require 'development_logger.rb'&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will &amp;#8220;monkey patch&amp;#8221; the Rails Logger, effectively overriding it&amp;#8217;s format_message method with our own mojo. Sure, it&amp;#8217;s not perfect. But it works great for development purposes. A more elegant way to do the same thing would be to subclass Logger and then do something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;config.logger = DevelopmentLogger.new(config.log_path)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, this just doesn&amp;#8217;t seem to have any effect when running script/server, which proceeds as if config.logger is set to the standard (unmodified) Rails Logger. I&amp;#8217;m at a bit of a loss as to why. If anyone can explain why setting config.logger seems to have no effect, please (please!) let me know.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>New Ruby/Rails IDE Comparison</title>
   <link href="http://blog.zerosum.org/2007/3/3/new-ruby-rails-ide-comparison.html" />
   <published>2007-03-03T00:00:00-05:00</published>
   <updated>2007-03-03T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/3/3/new-ruby-rails-ide-comparison</id>
   <content type="html">&lt;p&gt;Oh, what an &lt;span class="caps"&gt;IDE&lt;/span&gt; snob I&amp;#8217;ve become over the past couple years. I was an advocate of lightweight text editors for dev work for a long time, and was only truly bitten by the &amp;#8220;heavyweight&amp;#8221; environment bug once I was introduced to &lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ&lt;/a&gt;, which I can&amp;#8217;t say enough nice things about. I was obviously pretty psyched when I found out that the Jetbrains team has decided to put some serious effort into a Ruby plugin. It&amp;#8217;s become very usable in a very short amount of time, and I&amp;#8217;m very happy with it, but it&amp;#8217;s still relatively new and lacking some features.&lt;/p&gt;
&lt;p&gt;This &lt;a href="http://tnlessone.wordpress.com/2007/02/28/ruby-rails-ide-comparison-idea-netbeans-radrails/"&gt;new comparison of Ruby / Rails IDEs&lt;/a&gt; does a great job summarizing the features in the three leading &amp;#8220;heavyweight&amp;#8221; IDEs for Ruby / Rails. Definitely check it out if you&amp;#8217;re in the market for a good &lt;span class="caps"&gt;IDE&lt;/span&gt;. Interestingly, it seems like &lt;a href="http://www.netbeans.org"&gt;NetBeans&lt;/a&gt; is really giving both IntelliJ and RadRails a real run for their money, being the first of The Big Three to get a reasonable level of code completion working, amongst a plethora of other features.&lt;/p&gt;
&lt;p&gt;Although I&amp;#8217;ll probably download it and take a test drive, I&amp;#8217;m pretty committed to IntelliJ at this point, so I&amp;#8217;ll probably stick it out. But hopefully a little competition will keep things moving along at a good clip :-).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="caps"&gt;UPDATE&lt;/span&gt;: Switched over to NetBeans months ago and loving it! Nice work guys.&lt;/em&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>attr_readonly</title>
   <link href="http://blog.zerosum.org/2007/2/27/attr_readonly.html" />
   <published>2007-02-27T00:00:00-05:00</published>
   <updated>2007-02-27T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/2/27/attr_readonly</id>
   <content type="html">&lt;p&gt;I was really shocked yesterday to discover that there&amp;#8217;s literally no baked-in way to declare an ActiveRecord attribute as private or protected. Sometimes I don&amp;#8217;t want publicly-accessible ActiveRecord attribute methods. Sorry, but not every field in my database should have a corresponding public mutator.&lt;/p&gt;
&lt;p&gt;Consider an IP address field on a User model, that&amp;#8217;s used to record the last IP the user logged in from. This is something that, although clients outside of the model should be able to access the value, they certainly shouldn&amp;#8217;t be able to set it. Only the model itself should be able to update that field in the database. It&amp;#8217;s private!&lt;/p&gt;
&lt;p&gt;As another example, consider the case where a database field is just a cache of calculated relationship data. That cached value should never be set directly via a public instance method. One example is an average_rating as calculated from a bunch of user ratings on an article. Why would you want to expose a mechanism to set this directly? It should only be set through some sort of recalculate_average_rating public method that lives on your article model and fires as an after_save filter on a new rating object.&lt;/p&gt;
&lt;p&gt;It turns out that counter_cache itself suffers from this same problem. &lt;a href="http://dev.rubyonrails.org/ticket/6896"&gt;Ticket #6896 in the Rails Trac&lt;/a&gt; points out this exact issue and proposes a solution in the form of &lt;em&gt;attr_readonly&lt;/em&gt;. This is a solid solution, and would go a long ways towards enforcing proper encapsulation in AR.&lt;/p&gt;
&lt;p&gt;I ranted about this yesterday in freenode and got yelled at a little bit. Yes, I was probably being a bit obnoxious, but I also don&amp;#8217;t want the importance of this to be overlooked. The bottom line is that, like it or not, people are largely stupid. Programmers are not excluded from this. Even Ruby programmers, who admittedly are more self-conscious than most. If you give someone the opportunity to do something stupid, be it at the user level in your app, within your &lt;span class="caps"&gt;API&lt;/span&gt;, or right within the rest of your code base, they&amp;#8217;ll do it. If we&amp;#8217;re writing for an audience &amp;gt; 1, we should be writing code like we design user interfaces &amp;#8212; the public methods available on our classes shouldn&amp;#8217;t include things that give our audience permission to twiddle with the guts of that thing. This is a cornerstone of encapsulation and good OO design.&lt;/p&gt;
&lt;p&gt;So how do you feel about all this? Is it not A Big Deal to you? To me, it&amp;#8217;s a significant limiting factor when it comes to organizing large code bases amongst multiple programmers. If you&amp;#8217;re the only guy working on a hobby app, then fine, I guess you can police yourself. Go somewhere and do your thing. But if you&amp;#8217;re part of a larger team, or hope to build the foundation for something that can grow into a real enterprise-class app, then proper encapsulation is mandatory.&lt;/p&gt;
&lt;p&gt;I really hope that patch gets committed, or that someone puts together a plugin that delivers the same functionality. In the meantime, sure, there are some things you can do that are better than nothing at all. Try declaring a public mutator in your class to override the AR attribute method of the same name and raise NoMethodError, or write a before_save filter that loads up the model into another variable and replaces the current field with it&amp;#8217;s previous value. But just describing those &amp;#8220;solutions&amp;#8221; makes me feel somewhat ill. Rails is such a clean, elegant platform, and it needs a clean, elegant way to provide non-public methods for AR attributes. Let&amp;#8217;s get that patch committed :-).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Axiom Of The Empty Set</title>
   <link href="http://blog.zerosum.org/2007/2/23/axiom-of-the-empty-set.html" />
   <published>2007-02-23T00:00:00-05:00</published>
   <updated>2007-02-23T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/2/23/axiom-of-the-empty-set</id>
   <content type="html">&lt;p&gt;A list without any items in it is still a list, I must insist. Just like a box without anything in it is still a box, or a Smurf village without any Smurfs (Smurves?) is still a frickin Smurf villiage..&lt;/p&gt;
&lt;p&gt;But not according to the &lt;a href="http://www.w3.org/"&gt;W3C&lt;/a&gt;, apparently. File this one under Rant Of The Day: none of the standard &lt;a href="hhttp://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd"&gt;&lt;span class="caps"&gt;XHTML&lt;/span&gt; doctypes&lt;/a&gt; acknowledge the existance of the empty list.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;lt;!&lt;span class="caps"&gt;ELEMENT&lt;/span&gt; ul (li)+&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is, neither the &amp;lt;ul&amp;gt;&amp;lt;/ul&amp;gt; or the &amp;lt;ul/&amp;gt; representations are valid &lt;span class="caps"&gt;XHTML&lt;/span&gt;. This seems pretty broken to me at first glance, although I&amp;#8217;m certianly willing to hear a rebuttal if anyone has one. Even if you don&amp;#8217;t think it&amp;#8217;s busted, it certainly adds complication to a very common web dev scenario&amp;#8230;&lt;/p&gt;
&lt;p&gt;So we have a list of resources in our view and there&amp;#8217;s a good possibility that our list is empty. We want to be able to display that list, and have a button on the page that lets me add new items to the list with a little Ajax love so that we don&amp;#8217;t have to reload the page. If we can represent an empty list in the page, it&amp;#8217;s simple: we can just &lt;em&gt;render :update&lt;/em&gt; in Rails&amp;#8230;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;render :update do |page|
  page.insert_html(:bottom, :my_list, "&amp;lt;li&amp;gt;#{item}&amp;lt;/li&amp;gt;")
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code above assumes that there&amp;#8217;s a &lt;span class="caps"&gt;DOM&lt;/span&gt; ID &amp;#8216;my\_list&amp;#8217; that has 0 or more elements. But since &lt;span class="caps"&gt;XHTML&lt;/span&gt; won&amp;#8217;t let us represent a 0-element list, the obvious thing to do is to bake some extra smarts into the update code.&lt;/p&gt;
&lt;p&gt;Now it&amp;#8217;s the job of the update to determine if a list exists, and if not to create it, but only for the special one-off case of the zero element list? Yuck, bleh. No thanks. This is probably what most people do, but it just strikes me as putting too much intelligence into something that&amp;#8217;s supposed to be pretty dumb.&lt;/p&gt;
&lt;p&gt;The alternate solution listed here also qualifies as a hack, no bones about it. But, at least in my opinion, it&amp;#8217;s a somewhat more elegant hack than what was described above. File under simple Workaround Of The Day:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;ul id="list_things"&amp;gt;
  &amp;lt;li class="invisible" style="display: none"/&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the W3C does support empty list item elements :-). Thanks to azta for the suggestion.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Super Mathematics</title>
   <link href="http://blog.zerosum.org/2007/2/20/super-mathematics.html" />
   <published>2007-02-20T00:00:00-05:00</published>
   <updated>2007-02-20T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/2/20/super-mathematics</id>
   <content type="html">&lt;p&gt;&lt;img src="http://img158.imageshack.us/img158/5540/supermathematicsiz1.jpg"/&gt;&lt;br/&gt;
Do the math. No matter what you think, nobody&amp;#8217;s perfect.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>NH Ruby UG Meeting.002 Tuesday</title>
   <link href="http://blog.zerosum.org/2007/2/19/nh-ruby-ug-meeting-002-tuesday.html" />
   <published>2007-02-19T00:00:00-05:00</published>
   <updated>2007-02-19T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/2/19/nh-ruby-ug-meeting-002-tuesday</id>
   <content type="html">&lt;p&gt;If you&amp;#8217;re a Ruby developer (or just an interested outsider) living in southern Maine/NH or the northern Mass area, don&amp;#8217;t forget to attend the next meeting of the &lt;a href="http://wiki.nhruby.org/index.php/Upcoming_meetings"&gt;NH Ruby/Rails User Group&lt;/a&gt;. Discussion topic this week is &lt;span class="caps"&gt;RJS&lt;/span&gt; and Ajax. Come hang out with us in Portsmouth tomorrow and make sure to stick around afterwards for drinks, discussion, and merriment.&lt;/p&gt;
&lt;p&gt;Oh yeah, and &lt;a href="http://blog.zenlinux.com/"&gt;Scott&lt;/a&gt; has some free stuff to give away at the gathering too. You like free stuff, don&amp;#8217;t you?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>8.5 Minutes</title>
   <link href="http://blog.zerosum.org/2007/2/17/8-5-minutes.html" />
   <published>2007-02-17T00:00:00-05:00</published>
   <updated>2007-02-17T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/2/17/8-5-minutes</id>
   <content type="html">&lt;p&gt;What were you doing for those eight and a half minutes? &lt;br /&gt;
Was it mean, was it petty, or did you realize you were sorry &lt;br /&gt;
And that you love them?&lt;/p&gt;
&lt;p&gt;It&amp;#8217;d be nice to think we could get it right down here just once. &lt;br /&gt;
G*d bless the Plan.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Inheritance vs Relational Databases in RoR</title>
   <link href="http://blog.zerosum.org/2007/2/16/inheritance-vs-relational-databases-in-ror.html" />
   <published>2007-02-16T00:00:00-05:00</published>
   <updated>2007-02-16T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/2/16/inheritance-vs-relational-databases-in-ror</id>
   <content type="html">&lt;p&gt;There are three patterns in common use that deal with mapping object inheritance to relational databases. We didn&amp;#8217;t discuss any of them in my graduate databases course (sigh), and our friend &lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html"&gt;ActiveRecord&lt;/a&gt; implements only one of them: &lt;strong&gt;Single Table Inheritance&lt;/strong&gt; (&lt;span class="caps"&gt;STI&lt;/span&gt;).&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;STI&lt;/span&gt; is what you use when you want to represent an object hierarchy by mapping the union of all attributes found in that class hierarchy to a single underlying database table. Yup, it&amp;#8217;s a mouthful. And it works great if the attributes available on the subclasses all tend to be very similar. It&amp;#8217;s very fast (comparatively), but makes poor use of space since unused fields are just left null. ActiveRecord&amp;#8217;s implementation uses a &lt;em&gt;type&lt;/em&gt; field in the database to identify the subclass that the row belongs to.&lt;/p&gt;
&lt;p&gt;So what about alternative approaches? There are a couple&amp;#8230;&lt;br /&gt;
&lt;!--break--&gt;&lt;br /&gt;
First up is &lt;strong&gt;Concrete Table Inheritance&lt;/strong&gt;, in which there are n database tables for n concrete classes in the hierarchy. Although I&amp;#8217;m sure there are cases where this &lt;em&gt;must&lt;/em&gt; be useful, I can&amp;#8217;t think of a single one. The problem is the silly amount of replication that happens here &amp;#8212; fields common to classes will get replicated across tables. This means a lot of replication, more and more as the object hierarchy gets deeper, and a lot of difficulty when it gets to be refactoring time. Bleh, no thanks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Class Table Inheritance&lt;/strong&gt;, by contrast, has a table for each class, including interior nodes in the hierarchy (classes that have derivations).  A subclass is represented at the database layer as a table that has some number of additive fields plus a foreign key to it&amp;#8217;s parent class, which contains the fields that are common to all ancestors.&lt;/p&gt;
&lt;p&gt;Conceptually, this seems like the cleanest strategy to me, and the most &amp;#8220;OO&amp;#8221; of the approaches. However, when we think about the implementation, we realize that performance is going to be a big issue: the class-table strategy is going to require n joins for an object nested n levels into a class hierarchy. Ouch.&lt;/p&gt;
&lt;p&gt;Despite that admittedly ugly problem, there has been some interest in implementing Class Table Inheritance in ActiveRecord. In fact there&amp;#8217;s some &lt;a href="http://wiki.rubyonrails.org/rails/pages/ClassTableInheritanceInRails"&gt;contributed code on the Rails wiki&lt;/a&gt; that should allow you to use it as an alternative to &lt;span class="caps"&gt;STI&lt;/span&gt; in Rails. Someone should plugin-ize it, perhaps.&lt;/p&gt;
&lt;p&gt;I initially set out to look at alternative DB/object mappings because I was frustrated by the fact that &lt;span class="caps"&gt;STI&lt;/span&gt; wasn&amp;#8217;t &amp;#8220;accommodating&amp;#8221; enough for me. At one point I thought that Class Table Inheritance might be a better match for a specific problem we were looking to solve. It turns out that wasn&amp;#8217;t really the case at all; The problem wasn&amp;#8217;t &lt;span class="caps"&gt;STI&lt;/span&gt;, it was the way our object hierarchy was structured.&lt;/p&gt;
&lt;p&gt;My Lesson Of The Day for February 16th, 2007: If your object hierarchy is relatively shallow, and the single table strategy produces ugly results for you (lots of null fields on subclasses), take another look at the relationships between your objects. &lt;span class="caps"&gt;STI&lt;/span&gt; is a great fit for things that are very closely related to the parent class and require few extra attributes to express that. It&amp;#8217;s a lousy fit, otoh, for object relations that aren&amp;#8217;t tight like rockstar pants. If both CarPart and DogLeash share the parent class Purchase, they&amp;#8217;re probably not good candidates for &lt;span class="caps"&gt;STI&lt;/span&gt; (wink, wink).&lt;/p&gt;
&lt;p&gt;Embarrassed as I am to admit it, that was sort of the problem. More on that later, maybe.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Going Solo: Resources Without The 'S'</title>
   <link href="http://blog.zerosum.org/2007/2/13/going-solo-resources-without-the-s.html" />
   <published>2007-02-13T00:00:00-05:00</published>
   <updated>2007-02-13T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/2/13/going-solo-resources-without-the-s</id>
   <content type="html">&lt;p&gt;In case you missed it in the release announcement for Rails 1.2.2 last week, singular resources are now available in &lt;a href="http://api.rubyonrails.org/classes/ActionController/Resources.html"&gt;ActionController&lt;/a&gt;. You can use them to model singleton resources in your application.&lt;/p&gt;
&lt;p&gt;So we&amp;#8217;re using technoweenie&amp;#8217;s &lt;a href="http://svn.techno-weenie.net/projects/plugins/restful_authentication/"&gt;restful_authentication&lt;/a&gt; plugin to handle all things authentication-related in our current project, and decided that a singular resource was a good fit for a Session (login, logout) and Account Controller.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s a dumbass-simple example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;map.resource :account, :member =&amp;gt; { :activate =&amp;gt; :any }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the missing &amp;#8216;s&amp;#8217;. No collections for us here, no sir. But what &lt;em&gt;do&lt;/em&gt; we get?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span class="caps"&gt;GET&lt;/span&gt; /account =&amp;gt; AccountController#show&lt;br /&gt;
&lt;span class="caps"&gt;GET&lt;/span&gt; /account/new =&amp;gt; AccountController#new&lt;br /&gt;
&lt;span class="caps"&gt;POST&lt;/span&gt; /account =&amp;gt; AccountController#create&lt;br /&gt;
&lt;span class="caps"&gt;GET&lt;/span&gt; /account;edit =&amp;gt; AccountController#edit&lt;br /&gt;
&lt;span class="caps"&gt;PUT&lt;/span&gt; /account =&amp;gt; AccountController#update&lt;br /&gt;
&lt;span class="caps"&gt;DELETE&lt;/span&gt; /account =&amp;gt; AccountController#delete&lt;br /&gt;
(&lt;span class="caps"&gt;ANY&lt;/span&gt;) /account;activate =&amp;gt; AccountController#activate&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hey, that&amp;#8217;s just what I needed. And of course we get the standard named routes for the resource like account_url, account_path, etc. Yay for Resources. Yay for &lt;span class="caps"&gt;REST&lt;/span&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>ActiveRecord Association Extensions</title>
   <link href="http://blog.zerosum.org/2007/2/8/activerecord-association-extensions.html" />
   <published>2007-02-08T00:00:00-05:00</published>
   <updated>2007-02-08T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/2/8/activerecord-association-extensions</id>
   <content type="html">&lt;p&gt;So this is probably old hat to a lot of you, but for those that don&amp;#8217;t know, ActiveRecord Association Extensions are a seriously useful widget to have in your &lt;a href="http://snard.com/sg/guide/?ep=81&amp;fmt=0"&gt;Batman Fantasy Camp&lt;/a&gt; utility belt.&lt;/p&gt;
&lt;p&gt;You&amp;#8217;ve no doubt noticed that when you define an association between models, you get a bunch of nifty methods on the resultant collection like push, delete, count, uniq, and so on. But what if you want some bit of functionality defined on an association that isn&amp;#8217;t already baked in?&lt;/p&gt;
&lt;p&gt;Why we can extend our associations to define our own methods, of course. Let&amp;#8217;s see how&amp;#8230;&lt;/p&gt;
&lt;p&gt;Okay, so we have a relationship defined between two models: articles and opinions. An article has_many opinions. An opinion has a score on it, which is an integer between 1 and 10 representing how a user felt about the article.&lt;/p&gt;
&lt;p&gt;Using Association Extensions we can define our own method on the association itself, called total_score:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Article &amp;lt; ActiveRecord::Base
  has_many :opinions do
    def total_score
      sum(:score)
    end
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can access this information by writing something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;article.opinions.total_score&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Damn, that&amp;#8217;s intuitive. Maybe we want to add another method on the association to retrieve the average opinion of users who voted on this article today:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;has_many :opinions do
  def average_opinion_today
    find(:all, :conditions =&amp;gt; ["created_at &amp;gt;= current_date()"]).average
  end
end&lt;/code&gt;

&lt;code&gt;article.opinions.average_opinion_today&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And it gets better. If we find ourselves using the same extensions in more than one place, in true &lt;span class="caps"&gt;DRY&lt;/span&gt; spirit we can build a module and reuse it. When we use the :extend option in an association, we get all the methods in that module mixed in.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module MiscellaneousExtensions
  def average_opinion_today
    find(:all, :condition =&amp;gt; ["created_at &amp;gt;= current_date()"]).average
  end&lt;/code&gt;

&lt;code&gt;  def total_score
    sum(:score)
  end
end&lt;/code&gt;

&lt;code&gt;class Article &amp;lt; ActiveRecord::Base
  has_many :opinions, :extend =&amp;gt; MiscellaneousExtensions
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I put this module in a subdirectory of lib called extensions. You&amp;#8217;ll have to add that path to the config.load_paths in environment.rb in order for it to be recognized.&lt;/p&gt;
&lt;p&gt;Using these sorts of extensions on my own project earlier today really helped me clean up some troublesome model code. I was just so amped up about it that I had to share.&lt;/p&gt;
&lt;p&gt;For more information, see the &lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html"&gt;ActiveRecord::Associations &lt;span class="caps"&gt;API&lt;/span&gt; Reference&lt;/a&gt;. Oh and a big shout out to &lt;a href="http://www.workingwithrails.com/person/5220-brian-hoganrkingwithrails.com/"&gt;Brian Hogan&lt;/a&gt; for pointing me in the right direction.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Blog Package Ponderings</title>
   <link href="http://blog.zerosum.org/2007/1/28/blog-package-ponderings.html" />
   <published>2007-01-28T00:00:00-05:00</published>
   <updated>2007-01-28T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/1/28/blog-package-ponderings</id>
   <content type="html">&lt;p&gt;&lt;a href="http://drupal.org"&gt;Drupal&lt;/a&gt; has served me pretty well for a number of projects in the past. But as we shift our development focus towards Ruby-based projects, it seems like an ideal time to consider migrating my own blogging platform to something Rails-driven. Nothing against Drupal itself of course. Hell, for a &lt;span class="caps"&gt;PHP&lt;/span&gt; project it&amp;#8217;s pretty slick.&lt;/p&gt;
&lt;p&gt;But it still just leaves me feeling like I&amp;#8217;m flirting with an old (and somewhat unattractive) ex-girlfriend. It&amp;#8217;s not you, it&amp;#8217;s me.&lt;/p&gt;
&lt;p&gt;The obvious candidates seem to be &lt;a href="http://trac.typosphere.org/"&gt;Typo&lt;/a&gt; and &lt;a href="http://mephistoblog.com/"&gt;Mephisto&lt;/a&gt;. Another option would be to, of course, roll my own. But does the world really need another half-baked blogging engine? Probably not. If anyone has other recommendations let me know. Looks like I&amp;#8217;m leaning towards Mephisto at this point.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Markaby vs Haml vs ERB for Page Templates</title>
   <link href="http://blog.zerosum.org/2007/1/25/markaby-vs-haml-vs-erb-for-page-templates.html" />
   <published>2007-01-25T00:00:00-05:00</published>
   <updated>2007-01-25T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/1/25/markaby-vs-haml-vs-erb-for-page-templates</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been spending some time lately looking at different templating packages for Rails, in hopes of finding something cleaner and sexier than the standard &lt;span class="caps"&gt;ERB&lt;/span&gt; (rhtml) recipe, that also helps avoid common &lt;span class="caps"&gt;HTML&lt;/span&gt; pitfalls that cause pages not to validate.&lt;/p&gt;
&lt;p&gt;My search has pretty much boiled down to two candidates at this point. The first is &lt;a href="http://code.whytheluckystiff.net/markaby/"&gt;Markaby&lt;/a&gt;, which has been around for a while now and lets us represent our &lt;span class="caps"&gt;XHTML&lt;/span&gt; in Ruby code. The other candidate is the new kid on the block, &lt;a href="http://haml.hamptoncatlin.com/"&gt;Haml&lt;/a&gt;, which just reached a 1.0 last week and has it&amp;#8217;s own  proprietary &lt;span class="caps"&gt;CSS&lt;/span&gt;-ish syntax. Let&amp;#8217;s take a look at brief look at both of them&amp;#8230;&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s some &lt;span class="caps"&gt;ERB&lt;/span&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class="column" id="content"&amp;gt;
  &amp;lt;h2 class="entry_title"&amp;gt;&amp;lt;%= h @thing.name %&amp;gt;&amp;lt;/h2&amp;gt;
  &amp;lt;div class="entry_link"&amp;gt;&amp;lt;%= link_to('link', @thing.link) %&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is probably what we&amp;#8217;re all used to and there&amp;#8217;s no arguing that it works well enough, but&amp;#8230; Well, it&amp;#8217;s kind of ugly, isn&amp;#8217;t it? To represent this same thing in Markaby, we install the plugin and create a template with a &lt;em&gt;.mab&lt;/em&gt; extension and stick this in it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;div.column.content! {
  h2.entry_title @thing.name
  div.entry_link link_to 'link', @thing.link
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That sure looks better to me. Nice and compact, clean. The best part is that Markaby is actually valid Ruby syntax. This buys us a couple things: first of all, it means that our view won&amp;#8217;t run at all if we end up with a syntax error in it, which in turn means that it&amp;#8217;s valid &lt;span class="caps"&gt;XHTML&lt;/span&gt;. Slick.&lt;/p&gt;
&lt;p&gt;The downside is, of course, performance. It requires  rendering for every single tag and property, which makes it slow in comparison to &lt;span class="caps"&gt;ERB&lt;/span&gt;, since just the inline Ruby snippets in the rhtml file have to be processed and inserted into a mostly pre-rendered &lt;span class="caps"&gt;HTML&lt;/span&gt; template. I also have some minor gripes about the use of bang instead of pound for representing element IDs, and the fact that it &lt;a href="http://code.whytheluckystiff.net/markaby/ticket/23"&gt;blows up&lt;/a&gt; when I put a yield in my Markaby layout code (I have to use @content_for_layout, which is deprecated now).&lt;/p&gt;
&lt;p&gt;Anyway, enough about that. Let&amp;#8217;s talk about Haml for a second. Install the plugin, and create a view with a &lt;em&gt;.haml&lt;/em&gt; extension. Here&amp;#8217;s the same chunk of code we saw before written in Haml:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.column#content
  %h2.entry_title= @thing.name
  .entry_link= link_to('link', @thing.link)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Haml defines it&amp;#8217;s own syntax, which borrows from familiar &lt;span class="caps"&gt;CSS&lt;/span&gt; markup, and takes advantage of whitespace sensitivity for nesting. This latter bit is great news if you&amp;#8217;re one of those undercover Python people hiding amongst us (I&amp;#8217;m not one of you, now go away). It generates really nice clean appropriately nested &lt;span class="caps"&gt;HTML&lt;/span&gt; for output too.&lt;/p&gt;
&lt;p&gt;Although it&amp;#8217;s fairly easy to read and satisfies our cleanliness criteria, there are some immediate downsides to the fact that the markup is proprietary. Firstly, it means the files still have to be parsed and re-rendered by Rails, for a performance hit &amp;#8212; same as we&amp;#8217;d get with Markaby or any other higher-level template language for that matter. It also means that your editor isn&amp;#8217;t going to be able to help you with syntax highlighting unless it has explicit support through a plugin.&lt;/p&gt;
&lt;p&gt;I can see why people like Haml, it&amp;#8217;s compact and kind of fun (see the &lt;a href="http://haml.hamptoncatlin.com/tutorial"&gt;tutorial&lt;/a&gt; for more). But all things considered, I really can&amp;#8217;t see any reason I&amp;#8217;d use it instead of Markaby, which feels much more natural to me and has the added benefit of Ruby syntax validation. Perhaps if it were to represent a significant performance increase &amp;#8212; this seems doubtful &amp;#8212; but I haven&amp;#8217;t seen any real benchmarks. In any case, I don&amp;#8217;t think I&amp;#8217;ll be using it any time soon.&lt;/p&gt;
&lt;p&gt;If I were to choose one of these two, I&amp;#8217;d have to go with Markaby. I&amp;#8217;m quite smitten by the idea of writing template code in pure Ruby, and the syntax validation enforcement is extremely desirable. As bizarre as it may seem, I love the idea of a page failing to run because of a syntax error in my &amp;#8220;&lt;span class="caps"&gt;HTML&lt;/span&gt;&amp;#8221; markup. Still, the performance issues give me pause. An even bigger issue is that of fragment caching, which sadly seems to be &lt;a href="http://code.whytheluckystiff.net/markaby/ticket/26"&gt;currently busted&lt;/a&gt; in Markaby. So, all things considered, I guess I&amp;#8217;m sticking with &lt;span class="caps"&gt;ERB&lt;/span&gt; in my view templates, coupled with &lt;a href="http://redgreenblu.com/svn/projects/assert_valid_markup/README"&gt;assert_valid_markup&lt;/a&gt; for my validation testing needs. At least for now. Even thought it makes me cringe a bit.&lt;/p&gt;
&lt;p&gt;If I&amp;#8217;ve missed anything worth considering about either of these templates, or if there are other options, please drop me a line. I&amp;#8217;d love to hear what the rest of the community is using for their high-volume web apps&amp;#8230;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>IntelliJ Ruby Plugin 0.1 Beta Released</title>
   <link href="http://blog.zerosum.org/2007/1/22/intellij-ruby-plugin-0-1-beta-released.html" />
   <published>2007-01-22T00:00:00-05:00</published>
   <updated>2007-01-22T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/1/22/intellij-ruby-plugin-0-1-beta-released</id>
   <content type="html">&lt;p&gt;The kind folks over at JetBrains have finally got around to releasing a 0.1 Beta of their Ruby Plugin to the &lt;span class="caps"&gt;IDEA&lt;/span&gt; Repository. If you&amp;#8217;re an &lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ&lt;/a&gt; user, it&amp;#8217;s now as easy as going to the plugin manager in Preferences and selecting the Ruby plugin for installation. The workflow is the same as &lt;a href="http://blog.zerosum.org/?q=node/14"&gt;I described earlier&lt;/a&gt; but this release brings some important bugfixes; console output is now available, starting/stopping the WEBrick server now works as expected, etc.&lt;/p&gt;
&lt;p&gt;In case you haven&amp;#8217;t checked it out, the integrated Rails generators and Rake tasks rock, there&amp;#8217;s an RDoc toolbar with lookup, goto class functionality, code formatting, and a bunch of other goodies, all detailed in the &lt;a href="http://www.jetbrains.net/confluence/display/RUBYDEV/Ruby+Plugin+0.1+Release+Notes"&gt;Release Notes&lt;/a&gt;. I got all excited when I saw &lt;em&gt;keyword completion&lt;/em&gt; in the list; but it turns out that it&amp;#8217;s really just that &amp;#8212; although a ticket for proper code completion is listed in the &lt;a href="http://www.jetbrains.net/jira/browse/RUBY"&gt;issue tracker&lt;/a&gt; it looks like it&amp;#8217;ll still be awhile before we get to feel that love. Syntax highlighting in rhtml/builder templates will be huge also (in the roadmap).&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve been using RadRails as my RoR &lt;span class="caps"&gt;IDE&lt;/span&gt; so far, but now that the IntelliJ plugin is mature enough to work with I&amp;#8217;ll probably start migrating over. Don&amp;#8217;t get me wrong; RadRails is a &lt;em&gt;great&lt;/em&gt; project (and free!), but IntelliJ is my &lt;span class="caps"&gt;IDE&lt;/span&gt; of choice for Java dev, and I&amp;#8217;m psyched to see it evolving into a platform for Ruby development too.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rails 1.2.1, Prototype 1.5, Other Goodies...</title>
   <link href="http://blog.zerosum.org/2007/1/19/rails-1-2-1-prototype-1-5-other-goodies.html" />
   <published>2007-01-19T00:00:00-05:00</published>
   <updated>2007-01-19T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/1/19/rails-1-2-1-prototype-1-5-other-goodies</id>
   <content type="html">&lt;p&gt;Wow what a big day. Immediately after the release of Rails 1.2.0, we get a quickie bugfix bump to 1.2.1 and a great &lt;a href="http://weblog.rubyonrails.com/2007/1/19/rails-1-2-rest-admiration-http-lovefest-and-utf-8-celebrations"&gt;post by &lt;span class="caps"&gt;DHH&lt;/span&gt; summarizing the features in the release&lt;/a&gt;. On top of this, we get &lt;a href="http://www.prototypejs.org"&gt;Prototype 1.5.0, complete with a new web presence and some surprisingly good documentation&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Rails 1.2 Released</title>
   <link href="http://blog.zerosum.org/2007/1/18/rails-1-2-released.html" />
   <published>2007-01-18T00:00:00-05:00</published>
   <updated>2007-01-18T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/1/18/rails-1-2-released</id>
   <content type="html">&lt;p&gt;Looks like 1.2 has been officially released. I&amp;#8217;m sure that I&amp;#8217;m not the first to notice :-p. To update your gems:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gem update rails --source http://gems.rubyonrails.org --include-dependencies&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Seacoast Ruby UG First Meeting Tonight!</title>
   <link href="http://blog.zerosum.org/2007/1/16/seacoast-ruby-ug-first-meeting-tonight.html" />
   <published>2007-01-16T00:00:00-05:00</published>
   <updated>2007-01-16T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/1/16/seacoast-ruby-ug-first-meeting-tonight</id>
   <content type="html">&lt;p&gt;If you&amp;#8217;re in the seacoast NH area (north of Boston), don&amp;#8217;t forget to attend the first meeting of the Seacoast Ruby/Rails User Group tonight from 7-9 at the &lt;span class="caps"&gt;UNH&lt;/span&gt; campus. Apparently there was such an overwhelming response that Scott had to move the location to Morse Hall in order to accommodate the additional heads. Wow, cool. &lt;a href="http://blog.zenlinux.com/?p=75"&gt;More information and directions are on Scott&amp;#8217;s blog&lt;/a&gt;. See you there!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>FreeBSD 6.2 Released</title>
   <link href="http://blog.zerosum.org/2007/1/15/freebsd-6-2-released.html" />
   <published>2007-01-15T00:00:00-05:00</published>
   <updated>2007-01-15T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/1/15/freebsd-6-2-released</id>
   <content type="html">&lt;p&gt;FreeBSD 6.2 was released this morning. Lots of &lt;a href="http://www.freebsd.org/releases/6.2R/relnotes.html"&gt;bugfixes and new features&lt;/a&gt;, including official support for binary updates with freebsd-update. Cvsup away!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>RailsConf 2007 Registration Opens 1st Week Of February</title>
   <link href="http://blog.zerosum.org/2007/1/14/railsconf-2007-registration-opens-1st-week-of-february.html" />
   <published>2007-01-14T00:00:00-05:00</published>
   <updated>2007-01-14T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/1/14/railsconf-2007-registration-opens-1st-week-of-february</id>
   <content type="html">&lt;p&gt;&lt;a href="http://conferences.oreillynet.com/rails/"&gt;This time around&lt;/a&gt; the event runs from May 17th to the 20th. Am I gonna go? I&amp;#8217;m debating. It seems like a great opportunity to hear a bunch of great speakers, absorb some mad knoweldge, and meet like-minded Rubyists. Plus it&amp;#8217;s in Portland Oregon (the &lt;em&gt;other&lt;/em&gt; Portland), a city I&amp;#8217;ve always wanted to visit, and a mere 2 hours from a good friend of mine in Eugene.&lt;/p&gt;
&lt;p&gt;The thing that gives me pause is, of course, the cost. Registration is rumored to be a whopping $800 for the 4-day event this year, roughly double the 2006 event price. Ouch. Does this dramatic price hike reflect significantly increased offerings, or is it just because Rails has moved a bit closer to the mainstream &amp;#8212; meaning that more corporate entities are capable of coughing up the usual exorbitant conference fees to send employees? Sigh. In either case, as a self-employed developer type that&amp;#8217;s painful. Only half as painful as &lt;span class="caps"&gt;WWDC&lt;/span&gt;. But still, painful.&lt;/p&gt;
&lt;p&gt;Of course, if you have the time and the skills, &lt;a href="http://www.oreillynet.com/ruby/blog/2007/01/cd_baby_awards_free_railsconf.html"&gt;CD Baby is sponsoring a HackFest&lt;/a&gt; to send the top 20 patch contributors free of charge (inc hotel). You&amp;#8217;ve got until the 22nd to make your impact &lt;a href="http://workingwithrails.com/contests/hackfest2007"&gt;as measured here&lt;/a&gt;. And yes, I&amp;#8217;m a bit late in posting that news.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Stupid JavaScript Hacks</title>
   <link href="http://blog.zerosum.org/2007/1/7/stupid-javascript-hacks.html" />
   <published>2007-01-07T00:00:00-05:00</published>
   <updated>2007-01-07T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/1/7/stupid-javascript-hacks</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m usually not prone to &lt;span class="caps"&gt;MLP&lt;/span&gt; (mindless link propagation) but sometimes I just can&amp;#8217;t help it. Case in point: &lt;a href="http://www.destructoid.com/forum/viewtopic.php?t=1271&amp;highlight="&gt;this cool l&amp;#8217;il bit of JavaScript&lt;/a&gt;. Good for a quick chuckle.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>New Years Resolutions</title>
   <link href="http://blog.zerosum.org/2007/1/3/new-years-resolutions.html" />
   <published>2007-01-03T00:00:00-05:00</published>
   <updated>2007-01-03T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2007/1/3/new-years-resolutions</id>
   <content type="html">&lt;p&gt;Back from my requisite holiday visitations and feeling refreshed. Now it&amp;#8217;s time to get back to work. Here&amp;#8217;s some tentative goals for the new year:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Get up earlier in the morning. Start work earlier in the morning. Finish work earlier in the evening.&lt;/li&gt;
	&lt;li&gt;Focus more on Ruby this year, less on Java. Delete &lt;span class="caps"&gt;PHP&lt;/span&gt; from resume.&lt;/li&gt;
	&lt;li&gt;Get a gym membership and actually go on a regular basis.&lt;/li&gt;
	&lt;li&gt;Take a break from client (ie paid) work for a change and get one of my own ideas off the ground before summer.&lt;/li&gt;
	&lt;li&gt;Print some damn business cards. Stop coming up with cute excuses about why they&amp;#8217;re lame and learn to conform. Just a little.&lt;/li&gt;
	&lt;li&gt;Go to at least one conference. Go to at least one UG semi-regularly.&lt;/li&gt;
	&lt;li&gt;Bathe the dog more often. He is a stank factory.&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>NH Seacoast Ruby/Rails UG</title>
   <link href="http://blog.zerosum.org/2006/12/28/nh-seacoast-ruby-rails-ug.html" />
   <published>2006-12-28T00:00:00-05:00</published>
   <updated>2006-12-28T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2006/12/28/nh-seacoast-ruby-rails-ug</id>
   <content type="html">&lt;p&gt;I just got word that there&amp;#8217;s a Ruby on Rails user group starting up in my area. It&amp;#8217;s being organized by Scott Garman and the first meeting will be January 16th at the &lt;span class="caps"&gt;UNH&lt;/span&gt; Library in Durham, NH. More details at &lt;a href="http://blog.zenlinux.com/?p=53"&gt;Scott&amp;#8217;s Blog&lt;/a&gt;. It&amp;#8217;ll be great to meet some other local Ruby dorks &amp;#8212; most of my contract work is non-local and the other devs I know in the Portsmouth area have sadly yet to be bitten by the bug. I&amp;#8217;m psyched that someone has taken the initiative to set this up. Thanks Scott!&lt;/p&gt;
&lt;p&gt;On completely unrelated news, I&amp;#8217;ll be afk for a few days. Heading northbound to visit relatives and then some college friends for a New Years&amp;#8217; extravaganza of sorts. Hopefully I can remember how to play beer die &amp;#8212; it&amp;#8217;s been awhile. See y&amp;#8217;all in 2007!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Singin' Hobo (Not The Stabbin' Kind)</title>
   <link href="http://blog.zerosum.org/2006/12/26/singin-hobo-not-the-stabbin-kind.html" />
   <published>2006-12-26T00:00:00-05:00</published>
   <updated>2006-12-26T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2006/12/26/singin-hobo-not-the-stabbin-kind</id>
   <content type="html">&lt;p&gt;So it&amp;#8217;s the holidays, and I&amp;#8217;ve got some time &amp;#8220;off&amp;#8221; from &amp;#8220;work&amp;#8221; to recoup and think about my next project, play around with a few ideas, new toys&amp;#8230; The first thing on that list of toys is Tom Locke&amp;#8217;s &lt;a href="http://hobotek.net/blog/"&gt;Hobo&lt;/a&gt; framework.&lt;/p&gt;
&lt;p&gt;The Hobo 0.4.0 Gem was released late last week and it&amp;#8217;s pretty slick, although we&amp;#8217;re warned not to use it in production webapps yet :-). Hobo extends Rails in a number of ways, but the crux of it is that it lets you get up and running with a real, usable (and cleanly coded) Ruby-based webapp quicker than ever before. Hobo bundles in a working user system (acts_as_authenticated), permisisons, and a bunch of other goodies &amp;#8212; take a look at the &lt;a href="http://screencasts.hobocentral.net/hobo-pod-screencast.mov"&gt;screencast&lt;/a&gt; for a quickie walk-through. There also seem to be some interesting ideas here regarding tag libraries, but that&amp;#8217;s not covered in this first screencast. Anyway, definitely worth checking out.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>count_on counter_cache</title>
   <link href="http://blog.zerosum.org/2006/12/24/count_on-counter_cache.html" />
   <published>2006-12-24T00:00:00-05:00</published>
   <updated>2006-12-24T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2006/12/24/count_on-counter_cache</id>
   <content type="html">&lt;p&gt;Counter cache is my new friend. It&amp;#8217;s a very important little feature available on &lt;a href="http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html"&gt;ActiveRecord&lt;/a&gt; that makes counting associations efficient by maintaining a cache on the model.&lt;/p&gt;
&lt;p&gt;Although it&amp;#8217;s documented in &lt;span class="caps"&gt;AWDWR&lt;/span&gt; (p359 in my shiny new copy of the second edition), I guess it slipped my mind until now, so I thought I&amp;#8217;d blog about it just in case anyone else was looking for a solution&amp;#8230;&lt;/p&gt;
&lt;p&gt;So why does it rock so hard, you ask? Let&amp;#8217;s say that I&amp;#8217;m building &lt;span class="caps"&gt;YADRC&lt;/span&gt; (Yet Another Digg/Reddit Clone). I need to count the votes that users make to determine the popularity of an article, display that number, and use it to rank the order of the stories. So we set up our models: a story model, a vote model, and a user model, and we create the appropriate associations. Our &lt;em&gt;vote.rb&lt;/em&gt; is going to look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Vote &amp;lt; ActiveRecord::Base
  belongs_to :user
  belongs_to :story
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Predictably, Story has_many votes and User has_many votes. Now we can do something like this to find the number of votes on a story object:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Story.find(4).votes.size&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will work nicely right out of the box. However, once we have a significant amount of stories logged in our system and a reasonable number of votes on each story, performance goes straight to poop. The reason is that each time we&amp;#8217;re generating a score for a story (and remember, we&amp;#8217;ve got N stories), we&amp;#8217;re running a query like this against our database:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT count(*) AS count_all FROM votes WHERE (votes.story_id = 4) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we have any real amount of data in our system, this is going to get really ugly. Counter caching is one way to help counteract this problem. Let&amp;#8217;s rewrite our model to use it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Vote &amp;lt; ActiveRecord::Base
  belongs_to :user
  belongs_to :story, :counter_cache =&amp;gt; true
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also have to add a column, called votes_count, to the stories table in our database. Make sure to specify a default value of 0 in your &lt;span class="caps"&gt;DDL&lt;/span&gt;. Then we generate a migration, run it, and now we&amp;#8217;re ready to try again. The difference should be pretty dramatic. If we tail -f our development log, we&amp;#8217;ll notice that those count(*) queries aren&amp;#8217;t getting run anymore. So what&amp;#8217;s happening?&lt;/p&gt;
&lt;p&gt;ActiveRecord is using our counter cache column (called &lt;em&gt;votes_count&lt;/em&gt; in this case) on the stories table to store the number of belonging objects on the associate class. This value is incremented when an object of this class is created, and decremented when it&amp;#8217;s destroyed. The result is that we have a local &amp;#8220;cached count&amp;#8221; on the Story instance so we don&amp;#8217;t have to constantly query the votes table directly. Good deal, eh?&lt;/p&gt;
&lt;p&gt;There are two additional things worth noting about counter caching. As Dave Thomas points out in &lt;span class="caps"&gt;AWDWR&lt;/span&gt;, the counter won&amp;#8217;t get updated if entries are added by setting the link to the parent directly in the child like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vote = Vote.new
vote.story = story
vote.save&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&amp;#8217;re doing it this way, you&amp;#8217;ll have to force the parent class to refresh the collection. The right approach is to add a Vote through the Story object, which makes the parent aware of the increment (or decrement) and update the counter cache accordingly:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;story.vote.create&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The other point I wanted to make was that if you call the &lt;em&gt;count&lt;/em&gt; method on object instead of using &lt;em&gt;size&lt;/em&gt;, it will always run the actual count query on the underlying database, instead of using our cached shortcut. Thanks for the tip on that one, technoweenie.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>The Quest For The Perfect RoR IDE...</title>
   <link href="http://blog.zerosum.org/2006/12/22/the-quest-for-the-perfect-ror-ide.html" />
   <published>2006-12-22T00:00:00-05:00</published>
   <updated>2006-12-22T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2006/12/22/the-quest-for-the-perfect-ror-ide</id>
   <content type="html">&lt;p&gt;Ruby itself doesn&amp;#8217;t directly support multiple inheritance (yay for mixins) but the community sort of does. If you survey a random group of RoR developers, about half of them seem to come from a structured (oftentimes strongly-typed) OO language like Java, and the other half comes from the scripting world. One of the best things about Ruby is that it appeals equally to both camps. It&amp;#8217;s a common ground of sorts, a compromise, maybe the best of both worlds. I dig that.&lt;/p&gt;
&lt;p&gt;But as everyone knows, different backgrounds beget different toolsets. In the case of Ruby on Rails, it raises the question: do we need a real &lt;span class="caps"&gt;IDE&lt;/span&gt; for this kind of work, or is a simple text editor good enough?&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve gravitated back and forth between the two coding camps over the years. It&amp;#8217;s a &amp;#8220;right tool for the task&amp;#8221; sort of thing if you ask me. You want a lightweight project management application that runs on the web? &lt;span class="caps"&gt;PHP&lt;/span&gt; please. You want a robust scalable service for the delivery of digital media and have some money to spend? Let&amp;#8217;s do that one in Java. There&amp;#8217;s a religious war to be had here for sure, and I don&amp;#8217;t want to get into that&amp;#8230; The interesting thing (and the point I&amp;#8217;m trying to make) is that the tools you come to use and respond to differ depending on that background.&lt;/p&gt;
&lt;p&gt;When I&amp;#8217;m working in &lt;span class="caps"&gt;PHP&lt;/span&gt;, I use vim. No, really. I tried PHPEclipse and the pluses just didn&amp;#8217;t outweight the minuses for me. I also tried Komodo. I&amp;#8217;m an old school vi hacker, and I do all my sysadmin work in vi, so it became the natural choice. I don&amp;#8217;t regret it. Well, not often, anyway. After all, &lt;span class="caps"&gt;PHP&lt;/span&gt; is a scripting language, right?&lt;/p&gt;
&lt;p&gt;When I&amp;#8217;m working in Java, I&amp;#8217;m spoiled to death by &lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ&lt;/a&gt;. Yes, it&amp;#8217;s expensive. Yes, there&amp;#8217;s a learning curve. And yes, it&amp;#8217;s worth every damn penny/hour spent. I&amp;#8217;ve tried &lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt;. And it&amp;#8217;s alright, but it&amp;#8217;s not &lt;span class="caps"&gt;IDJ&lt;/span&gt;. The JetBrains guys have delivered what is by far the most intelligent, usable &lt;span class="caps"&gt;IDE&lt;/span&gt; I&amp;#8217;ve ever used. That&amp;#8217;s my story, and I&amp;#8217;m sticking to it.&lt;/p&gt;
&lt;p&gt;So is Ruby a scripting language, or is Ruby a proper OO &amp;#8220;enterprisey&amp;#8221; language? I&amp;#8217;d argue that it&amp;#8217;s both and that it&amp;#8217;s use dictates the classification. But when you&amp;#8217;re building Rails apps, you&amp;#8217;re firmly entrenched in OO/&lt;span class="caps"&gt;MVC&lt;/span&gt; proper webapp territory, and therefore, imho, that demands the use of a proper &lt;span class="caps"&gt;IDE&lt;/span&gt;. Particularly once a project becomes sufficiently large.&lt;/p&gt;
&lt;p&gt;So what do &lt;em&gt;I&lt;/em&gt; use when it comes to Rails work then? Well, up until now I&amp;#8217;ve been using &lt;a href="http://www.radrails.org"&gt;RadRails&lt;/a&gt; with &lt;span class="caps"&gt;RDT&lt;/span&gt; and Eclipse. It works pretty well for the most part. But it&amp;#8217;s no IntelliJ. We don&amp;#8217;t, of course, have auto-complete yet, but the syntax highlighting is getting there, the generators and rake tasks are wrapped up nicely, as is run output, test execution, etc etc. It&amp;#8217;s better, for me, than using vi, by leaps and bounds and it seems to be getting better and better (nice job guys!).&lt;/p&gt;
&lt;p&gt;RadRails seems to be the choice for Windows and Linux users, but everyone else I know on OS X seems to be using &lt;a href="http://macromates.com/"&gt;TextMate&lt;/a&gt;. Whoah, what? I&amp;#8217;ve never used TextMate &amp;#8212; am I missing out? But wait, TextMate is just a text editor right? It&amp;#8217;s &lt;span class="caps"&gt;NOT&lt;/span&gt; an &lt;span class="caps"&gt;IDE&lt;/span&gt; and doesn&amp;#8217;t aspire to be. Regardless, the popular opinion seems to be that it&amp;#8217;s &amp;#8220;good enough&amp;#8221;.&lt;/p&gt;
&lt;p&gt;So what do you use? Are you, like everyone else out there, a TextMate-phile? If so, why? Don&amp;#8217;t get me wrong, I &lt;em&gt;understand&lt;/em&gt; the allure of a minimalistic text editor for hacking script, but have you been spoiled by something as nice as &lt;span class="caps"&gt;IDJ&lt;/span&gt; in the past? Oh man would I kill for ctrl-space to autocomplete/interrogate an object to discover it&amp;#8217;s methods..&lt;/p&gt;
&lt;p&gt;I wonder if there are a lot of people who have come over from the Java side of things who have switched to TextMate, particularly people who have used IntelliJ in the past. Am I making a blanket assumption that most of the people using text editors to hack Rails are &lt;em&gt;not&lt;/em&gt; Java converts? Am I just overcomplicating the whole thing? Is TextMate really &amp;#8220;good enough&amp;#8221;?&lt;/p&gt;
&lt;p&gt;The entire Rails core team purportedly uses TextMate&amp;#8230; Maybe I&amp;#8217;m just missing something? I&amp;#8217;d love to hear your opinions.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;span class="caps"&gt;UPDATE&lt;/span&gt;: I&amp;#8217;m using &lt;a href="http://www.netbeans.org/community/releases/60/index.html"&gt;NetBeans&lt;/a&gt; now. And it&amp;#8217;s great.&lt;/em&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>IntelliJ On Rails</title>
   <link href="http://blog.zerosum.org/2006/12/22/intellij-on-rails.html" />
   <published>2006-12-22T00:00:00-05:00</published>
   <updated>2006-12-22T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2006/12/22/intellij-on-rails</id>
   <content type="html">&lt;p&gt;If you&amp;#8217;re an &lt;a href="http://www.jetbrains.com/idea/"&gt;IntelliJ&lt;/a&gt; user like me, and have recently been bitten by the RoR bug, you&amp;#8217;ll be glad to know that there&amp;#8217;s a plugin on the way. It&amp;#8217;s still in it&amp;#8217;s infancy, lacking a lot of features, and is therefore not in the repository, but that doesn&amp;#8217;t mean we can&amp;#8217;t play around with it. What follows is a brief tutorial on how to locate, install, and use the ruby plugin&amp;#8230;&lt;/p&gt;
&lt;p&gt;First you need to check out the sources from the Subversion repo:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;svn co http://svn.jetbrains.org/idea/Trunk/ruby&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use &lt;a href="http://ant.apache.org/"&gt;Ant&lt;/a&gt; to build it (run &lt;em&gt;ant&lt;/em&gt; from the directory you co&amp;#8217;d to, where the build.xml file lives). The build process should generate a jar file in dist/ called &lt;em&gt;ruby-&lt;span class="caps"&gt;SNAPSHOT&lt;/span&gt;.jar&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Next, make a new directory in your &lt;span class="caps"&gt;IDJ&lt;/span&gt; plugins directory called &amp;#8216;ruby&amp;#8217; and make a lib directory in there. Copy the jar to $IDJ_ROOT/plugins/ruby/lib. On OS X, this path is something like &lt;em&gt;/Applications/IntelliJ &lt;span class="caps"&gt;IDEA&lt;/span&gt; 6.0.2.app/plugins/ruby/lib/&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Start IntelliJ. Go to Settings &amp;#8594; Project Settiings &amp;#8594; Project Structure. In Global Resources, under JDKs, right click and add a Ruby &lt;span class="caps"&gt;SDK&lt;/span&gt;. On OS X, you&amp;#8217;ll want to point it at /usr/local, or whereever your copy of Ruby has been installed.&lt;/p&gt;
&lt;p&gt;Now you should be able to create a new project and select Ruby &lt;span class="caps"&gt;SDK&lt;/span&gt; from the &lt;span class="caps"&gt;JDK&lt;/span&gt; list (heh). Create a single module project, select Rails as your module type, and set the Ruby &lt;span class="caps"&gt;SDK&lt;/span&gt; for the module. Finally, you&amp;#8217;ll be given the chance to generate a new Rails application skeleton, generate missing files, or use an existing Rails app. Go ahead and create a test project and generate a new Rails framework. I&amp;#8217;ll do all the work for you and populate the project explorer with that oh-so-familiar directory structure. Check out that ugly Ruby icon they&amp;#8217;re using. Jeeze, what is that?&lt;/p&gt;
&lt;p&gt;Right click in the project explorer and select New &amp;#8594; Controller. Name your controller test and add an action name hello. Click OK. &lt;span class="caps"&gt;IDJ&lt;/span&gt; will run the Rails generator and update the project explorer. You now have a TestController with a hello action, the corresponding view template, and the expected test stubs.&lt;/p&gt;
&lt;p&gt;You can select Run &amp;#8594; Run&amp;#8230; to start a WEBrick server and test your app. There are some bugs here. First of all, there is no run output in the console view where you&amp;#8217;d expect it to be. No web browser is launched, no indication is given of what port number the server gets bound to. Worse, you can&amp;#8217;t seem to kill a running WEBrick server without killing the process from a terminal. So yeah, there&amp;#8217;s obviously still some work to do here. For now, I&amp;#8217;d suggest running WEBrick from the command line (&lt;a href="http://www.radrails.org"&gt;RadRails&lt;/a&gt; still wins here, at least). No command completion or real debugging support is available yet either, but hey.. it&amp;#8217;s a start. It&amp;#8217;s functional, you can run tests from within the &lt;span class="caps"&gt;IDE&lt;/span&gt;, you get basic code formatting, syntax highlighting, etc.&lt;/p&gt;
&lt;p&gt;For more information, check out the &lt;a href="http://www.jetbrains.net/confluence/display/RUBYDEV/Home"&gt;JetBrains Project Homepage&lt;/a&gt; for the ruby plugin, where you&amp;#8217;ll find a link to the roadmap and discussion groups. You&amp;#8217;ll note that there are plans for autocompletion, ability to browse to symbol, proper &lt;span class="caps"&gt;YAML&lt;/span&gt;, &lt;span class="caps"&gt;RXML&lt;/span&gt; support, etc. I really hope that development continues on this. &lt;span class="caps"&gt;IDJ&lt;/span&gt; is much-loved amongst the Java community, and could be a huge hit in the Rails community if they get a slick, fully functional plugin out there.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Develop with pleasure&lt;/em&gt; ;-).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Relief</title>
   <link href="http://blog.zerosum.org/2006/12/20/relief.html" />
   <published>2006-12-20T00:00:00-05:00</published>
   <updated>2006-12-20T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2006/12/20/relief</id>
   <content type="html">&lt;p&gt;So we just finished wrapping up work on the app we&amp;#8217;ve been building for the past 8 months. Yay! It&amp;#8217;s part of a suite of web-powered tools for a certain niche video editing system. Implemented in Java, leveraging Swing, Axis, WebObjects&amp;#8230; Great project and totally learned a lot, but sure am relieved to have delivered it. I&amp;#8217;m sure there&amp;#8217;ll be a tweak to make here or there, but you know&amp;#8230; It&amp;#8217;s delivered (rc).&lt;/p&gt;
&lt;p&gt;What&amp;#8217;s next? Well, I&amp;#8217;m not entirely sure to be honest. For the first time in my life I&amp;#8217;m thinking about abandoning paid work in order to invest a couple solid months of full-time effort working on the Ruby/Rails app that&amp;#8217;s in my head. Perhaps it&amp;#8217;s finally time to put my neck out there a little and make it happen. After all, I isn&amp;#8217;t getting any younger, now is I?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Searchable RoR Docs</title>
   <link href="http://blog.zerosum.org/2006/12/11/searchable-ror-docs.html" />
   <published>2006-12-11T00:00:00-05:00</published>
   <updated>2006-12-11T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2006/12/11/searchable-ror-docs</id>
   <content type="html">&lt;p&gt;One of the great things about &lt;span class="caps"&gt;PHP&lt;/span&gt; isn&amp;#8217;t the documentation, per se, but rather the centralized, searchable docs interface at &lt;a href="http://www.php.net"&gt;&lt;span class="caps"&gt;PHP&lt;/span&gt;.net&lt;/a&gt;. Big thanks to Jeremy Durham for putting together an equivalent &lt;a href="http://www.railsapi.org/"&gt;Rails resource site&lt;/a&gt;. There&amp;#8217;s obviously still a good bit of work to do before docs are as complete and usable as they could be, but an online searchable repository like this is definitely a step in the right direction. Bookmark it, and add some example code and comments mang.&lt;/p&gt;
&lt;p&gt;Oh and while we&amp;#8217;re talking about documentation (or lack thereof), don&amp;#8217;t forget to  &lt;a href="http://blog.caboo.se/pages/documentation_drive"&gt;donate&lt;/a&gt; to the Rails &lt;span class="caps"&gt;API&lt;/span&gt; docs project at Caboo.se if you haven&amp;#8217;t already.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>JavaScript Tricks (RJS-R): Cleaning Up My Mess...</title>
   <link href="http://blog.zerosum.org/2006/12/7/javascript-tricks-rjs-r-cleaning-up-my-mess.html" />
   <published>2006-12-07T00:00:00-05:00</published>
   <updated>2006-12-07T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2006/12/7/javascript-tricks-rjs-r-cleaning-up-my-mess</id>
   <content type="html">&lt;p&gt;So a couple folks have pointed out that the last Rails+YUI example I posted doesn&amp;#8217;t work in IE. Or Safari. Eek, that&amp;#8217;s not so good.&lt;/p&gt;
&lt;p&gt;Anyway, this post is kind of a hodgepodge documenting the process I went through to fix those issues and clean it up a bit. Maybe more of a &amp;#8216;note to self&amp;#8217; than an actual blog entry, so not required reading by any means. Unless you&amp;#8217;re having issues with IE and &lt;a href="http://www.danwebb.net/2006/11/24/minusmor-released"&gt;Minus &lt;span class="caps"&gt;MOR&lt;/span&gt;&lt;/a&gt; that is, in which case the magic word is &lt;i&gt;content-type&lt;/i&gt;. I&amp;#8217;m embarassed to say how much sleep I lost tracking that one down. Sigh.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class ExampleController &amp;lt; ApplicationController
  layout "standard", :except =&amp;gt; :add&lt;/code&gt;

&lt;code&gt;  def show
  end&lt;/code&gt;

&lt;code&gt;  def add
    @response.headers['content-type'] = 'text/javascript';
    @thing = params[:thing]
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#8217;s our updated &lt;i&gt;ExampleController&lt;/i&gt;. Notice that we&amp;#8217;re setting the content type of the response in the headers now. The default content type appears to be html, instead of text/javascript. Not entirely sure why this is happening at the moment as Minus-R appears to set the content-type in it&amp;#8217;s render method. But anyway, for whatever reason, Safari and Firefox both work fine, but IE doesn&amp;#8217;t like it one bit. Of course, instead of warning us (or giving us an option to warn us, for that matter) it simply discards the asynchronous response. Hence, we never see an update. Nice, eh?&lt;/p&gt;
&lt;p&gt;I also took the opportunity clean up the rest of our example a little bit. Here&amp;#8217;s our new layout template:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;title&amp;gt;YUI Tester: &amp;lt;%= controller.action_name %&amp;gt;&amp;lt;/title&amp;gt;
  &amp;lt;%= javascript_include_tag "yui/yahoo", "yui/event", "yui/dom", "yui/dragdrop", "yui/connection", "yui/container"%&amp;gt;
  &amp;lt;%= stylesheet_link_tag  'yui/container'%&amp;gt;&lt;/code&gt;

&lt;code&gt;  &amp;lt;script language="javascript"&amp;gt;
    YAHOO.namespace("yuitest.container");&lt;/code&gt;

&lt;code&gt;    function init() {
      var handleCancel = function() { this.cancel(); };
      var handleSubmit = function() { this.submit(); };
      var handleFailure = function(o) { alert("failure: " + o.responseText); };
      var handleSuccess = function(o) { eval(o.responseText); };&lt;/code&gt;

&lt;code&gt;      YAHOO.yuitest.container.myDialog = new YAHOO.widget.Dialog("myDialog", {
        width: "500px",
        modal: true, 
        visible: false,
        fixedcenter: true, 
        constraintoviewport: true, 
        draggable: true });&lt;/code&gt;

&lt;code&gt;      var escKeyListener = new YAHOO.util.KeyListener(document, { keys : 27 }, 
        {fn:handleCancel,scope:YAHOO.yuitest.container.myDialog,correctScope:true} );&lt;/code&gt;

&lt;code&gt;      YAHOO.util.Event.addListener( 'myDialogForm', 'submit', function(e) {
        YAHOO.util.Event.preventDefault(e);
        YAHOO.yuitest.container.myDialog.submit();
      });&lt;/code&gt;
        
&lt;code&gt;      YAHOO.yuitest.container.myDialog.cfg.queueProperty("keylisteners", escKeyListener);
      YAHOO.yuitest.container.myDialog.cfg.queueProperty("buttons",
        [{ text:"Save", handler:handleSubmit, isDefault:true },{ text:"Cancel", handler:handleCancel } ]);&lt;/code&gt;

&lt;code&gt;      YAHOO.yuitest.container.myDialog.callback = {
        success: handleSuccess,
        failure: handleFailure
      };&lt;/code&gt;

&lt;code&gt;      YAHOO.yuitest.container.myDialog.render();
    }&lt;/code&gt;

&lt;code&gt;    function addThing() {
      YAHOO.yuitest.container.myDialog.show();
    }&lt;/code&gt;

&lt;code&gt;    YAHOO.util.Event.addListener(window, "load", init);
  &amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;div id="main"&amp;gt;
    &amp;lt;% if flash[:notice] -%&amp;gt;
      &amp;lt;div id="notice"&amp;gt;&amp;lt;%= flash[:notice] %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;% end -%&amp;gt;
    &amp;lt;%= @content_for_layout %&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;OK, a bunch of changes there. First, we&amp;#8217;ve removed all the Prototype JS libs because we no longer need it &amp;#8212; YUI&amp;#8217;s connection manager can take care of this stuff for us, and since we&amp;#8217;re not using the default behavior of &lt;span class="caps"&gt;RJS&lt;/span&gt;, there are no worries about dependence on Prototype. Next, we&amp;#8217;ve added a couple &lt;a href="http://developer.yahoo.com/yui/examples/container/keylistener/1.html"&gt;key listeners&lt;/a&gt; on the popup dialog to handle enter (submit) and escape (cancel). Note that we have to use &lt;em&gt;Event.preventDefault()&lt;/em&gt; in our enter key listener to suppress the default form submission action. Otherwise, we end up redirected to a new page that just contains our result string, and we don&amp;#8217;t want that&amp;#8230;&lt;/p&gt;
&lt;p&gt;Finally, we&amp;#8217;ve also eliminated the clumsy body of the success handler and replaced it with a single statement: &lt;em&gt;eval(o.responseText)&lt;/em&gt;. Yup, we can just evaluate the JavaScript returned from our Rails app. No need to append a new script tag to the body, yehck. Here&amp;#8217;s the code that&amp;#8217;s returned from our add.ejs template, as a reminder (it&amp;#8217;s unchanged):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;document.getElementById('hello_msg').innerHTML = '&amp;lt;%=@thing[:name]%&amp;gt;';&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So yeah, it just replaces the inner &lt;span class="caps"&gt;HTML&lt;/span&gt; in the element named &lt;em&gt;hello_msg&lt;/em&gt;. Easy enough. The next step here would be to figure out how to encapsulate the stuff in the layout using some sort of helper module or plugin. But that&amp;#8217;s it for now.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Progress on my current Rails project has been pretty slow lately, as we&amp;#8217;re nearing completion on a big client project (a slick Java-based webstart app that&amp;#8217;s been occupying the majority of my time for the past 6 or so months). It&amp;#8217;s nice to finally see the light at the end of the tunnel! Hopefully once that wraps, we&amp;#8217;ll have some significant time to pour into the RoR ideas and prototypes we&amp;#8217;ve been playing around with&amp;#8230;)&lt;/em&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>RJS &amp; MinusMOR</title>
   <link href="http://blog.zerosum.org/2006/12/2/rjs-minusmor.html" />
   <published>2006-12-02T00:00:00-05:00</published>
   <updated>2006-12-02T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2006/12/2/rjs-minusmor</id>
   <content type="html">&lt;p&gt;&lt;span class="caps"&gt;RJS&lt;/span&gt; rocks. It lets me write JavaScript without writing any JavaScript. That&amp;#8217;s very Zen, and I like it. But sometimes I find myself writing really ugly, narsty things in my &lt;span class="caps"&gt;RJS&lt;/span&gt; templates. Instead of using Ruby to write JavaScript I end up writing JavaScript and appending it to the page with Ruby, especially when client side conditionals are involved. Needless to say, the template code quickly devolves into what can only be described as frankenrubyscript.&lt;/p&gt;
&lt;p&gt;To rid ourselves of the monster, take a look at Dan Webb&amp;#8217;s &lt;a href="http://www.danwebb.net/2006/11/24/minusmor-released"&gt;MinusMOR&lt;/a&gt; plugin, which lets you return plain ol JavaScript to the browser using templates with an &lt;em&gt;.ejs&lt;/em&gt; file extension. This may not seem like a big deal but it&amp;#8217;s pretty damn helpful if you return any significant amount of client-side logic within &lt;span class="caps"&gt;RJS&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;[Note that you&amp;#8217;ll need to be on the Rails 1.2 codebase to use the plugin]&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As a simple example, let&amp;#8217;s overhaul our sample &lt;span class="caps"&gt;YUI&lt;/span&gt; test app to use MinusMOR. Now this really isn&amp;#8217;t a great example, as the JavaScript code is super simple and therefore lends itself well to being written in Ruby. But oh well. At least it gives you an idea of how it works.&lt;/p&gt;
&lt;p&gt;Our &lt;em&gt;add.rjs&lt;/em&gt; file used to contain the following one-liner:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;page.replace_html 'hello_msg', @thing[:name]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, our &lt;em&gt;add.ejs&lt;/em&gt; file will contain the following code instead. Note the use of ERb in the template:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;document.getElementById('hello_msg').innerHTML = '&amp;lt;%=@thing[:name]%&amp;gt;';&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case the normal &lt;span class="caps"&gt;RJS&lt;/span&gt; approach is quicker, sexier, and, above all else, easier to read. And, admittedly, 90% of your client-side code will more than likely be the simple kind of stuff that &lt;span class="caps"&gt;RJS&lt;/span&gt; rocks at (&lt;em&gt;update this text within that &lt;span class="caps"&gt;DIV&lt;/span&gt;&lt;/em&gt;, &lt;em&gt;switch the visible state of that &lt;span class="caps"&gt;DOM&lt;/span&gt; element to hidden&lt;/em&gt;, etc). But you can certainly imagine scenarios where it&amp;#8217;d make sense to write pure JavaScript in the template instead.&lt;/p&gt;
&lt;p&gt;Use &lt;span class="caps"&gt;RJS&lt;/span&gt; wherever you can, but once bits and pieces of frankenrubyscript start sneaking into your code, be sure to check out Dan&amp;#8217;s plugin. Cuz there&amp;#8217;s no denying that there are cases where using plain ol JavaScript is cleaner, as un-Zen-like as that may seem&amp;#8230;.!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Moving To The Edge, Or Thereabouts</title>
   <link href="http://blog.zerosum.org/2006/11/27/moving-to-the-edge-or-thereabouts.html" />
   <published>2006-11-27T00:00:00-05:00</published>
   <updated>2006-11-27T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2006/11/27/moving-to-the-edge-or-thereabouts</id>
   <content type="html">&lt;p&gt;So I tried to update my OS X dev box to GemRails 1.2 RC 1 and ran into some issues the other day. For some reason, I just couldn&amp;#8217;t seem to get system Rails pointing to the new (.5618) copy. I&amp;#8217;m usually a pretty stubborn bastard, but one of the plugins I wanted to use requires &lt;em&gt;exempt_from_layout&lt;/em&gt; to be available on ActionController::Base, so I figured I&amp;#8217;d use &lt;a href="http://wiki.rubyonrails.com/rails/pages/EdgeRails"&gt;EdgeRails&lt;/a&gt; and freeze a copy of 1.2 RC 1 in the project&amp;#8217;s vendors directory.&lt;/p&gt;
&lt;p&gt;One of the nice things about the way this is all wired together is that you don&amp;#8217;t have to be on the very edge of EdgeRails to take advantage of it. In this case, I just need some functionality in 1.2 RC 1 so I can update our existing project and check out using the tag:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake rails:freeze:edge TAG=rel_1-2-0_RC1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To verify that we&amp;#8217;re on EdgeRails now using the 1.2 codebase (so we can hang out with the cool kids), we can run &lt;em&gt;script/about&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Edge Rails revision          rel_1-2-0_RC1&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Keep in mind that this is different than just doing a regular edge freeze since we know we&amp;#8217;re getting exactly what we&amp;#8217;re asking for. If we just issued an edge freeze without the &lt;span class="caps"&gt;TAG&lt;/span&gt; parameter we&amp;#8217;re going to get the latest and greatest development version which of course means two things: 1) we get the bestest newest coolest stuff, and 2) there&amp;#8217;s a good chance that some of that stuff is a bit buggy.&lt;/p&gt;
&lt;p&gt;For the moment, we don&amp;#8217;t have an immediate need to be running the very latest and will therefore generally tend toward valuing stability over freshness. But as our projects grow and we shed more and more of our noobskin, I&amp;#8217;m sure we&amp;#8217;ll begin making even more exceptions to that rule, forcing us ever closer to the bleeding edge.&lt;/p&gt;
&lt;p&gt;Pun intended, of course.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Happy Thanksgiving: Rails 1.2 RC 1 Arrives!</title>
   <link href="http://blog.zerosum.org/2006/11/23/happy-thanksgiving-rails-1-2-rc-1-arrives.html" />
   <published>2006-11-23T00:00:00-05:00</published>
   <updated>2006-11-23T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2006/11/23/happy-thanksgiving-rails-1-2-rc-1-arrives</id>
   <content type="html">&lt;p&gt;In case you haven&amp;#8217;t already heard, Rails 1.2 RC 1 is out. Click &lt;a href="http://weblog.rubyonrails.com/2006/11/23/rails-1-2-release-candidate-1"&gt;here&lt;/a&gt; for details. Taking center stage this time seems to be the push towards creating &lt;a href="http://www.peej.co.uk/articles/restfully-delicious.html"&gt;RESTful&lt;/a&gt; services. Very nice. Also updates to Prototype and Script.aculo.us and, whoah, some &lt;a href="http://i.nfectio.us/articles/2006/11/02/deprecations-in-rails-1-2"&gt;deprecations&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So after you finish wolfing down that enormous, weight-altering dinner, sit back in your tryptophan-induced haze and take a gander over the new stuff. Me? Nah. I&amp;#8217;m headed up to the Great White North for a couple of Internet-free days. But I know what I&amp;#8217;ll be doing when I get back&amp;#8230; Enjoy!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Prototype vs YUI Connection Manager: Dialog Continued...</title>
   <link href="http://blog.zerosum.org/2006/11/20/prototype-vs-yui-connection-manager-dialog-continued.html" />
   <published>2006-11-20T00:00:00-05:00</published>
   <updated>2006-11-20T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2006/11/20/prototype-vs-yui-connection-manager-dialog-continued</id>
   <content type="html">&lt;p&gt;In the last &lt;a href="http://www.zerosum.org/devblog/?q=node/4"&gt;blog entry&lt;/a&gt;, I wrote about doing a first pass integration between Rails and the Yahoo UI Library&amp;#8217;s Dialog widget. In the event handler for the save action, we created an Ajax.Request object using the &lt;a href="http://prototype.conio.net/"&gt;Prototype&lt;/a&gt; library to make the Ajax call but I didn&amp;#8217;t elaborate on why just calling this.submit() in the handler wouldn&amp;#8217;t work. Well, the answer is pretty obvious: I wanted to tease out a second article :-).&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;YUI&lt;/span&gt; expects us to set up a callback handler for the success/failure of the XMLHttpRequest request that it generates when this.submit() is called. If you don&amp;#8217;t have a callback set up, the client receives the response but just ends up throwing it away. So let&amp;#8217;s look into how we need to change our handler to do things the &amp;#8220;right&amp;#8221; way (according to Yahoo, anyway). We&amp;#8217;ll also see how this is somewhat at odds with Prototype and &lt;span class="caps"&gt;RJS&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;YUI&amp;#8217;s &lt;a href="http://developer.yahoo.com/yui/connection/"&gt;Connection Manager&lt;/a&gt; utility exists to simplify your interface to the XMLHttpRequest object and provides a handler pattern for callbacks. It&amp;#8217;s used throughout their library, so let&amp;#8217;s use it here. This updated code should obviate the need for using Prototype in the body of the save action handler:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var handleSubmit = function() {
  this.callback = {
    success: function(o) {
      var scriptObj = document.createElement("script");
      scriptObj.setAttribute("type", "text/javascript");
      scriptObj.text = o.responseText;
      document.body.appendChild(scriptObj);
    },
    failure: function(o) { 
      // do something here
      alert(o.responseText);
    }
  };
  this.submit();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the code listing above, we define the callback object to handle the success / failure cases reported by XMLHttpRequest. On success, we&amp;#8217;re going to create a new script element in the &lt;span class="caps"&gt;DOM&lt;/span&gt; and load it up with the response that our &lt;span class="caps"&gt;RJS&lt;/span&gt; template renders. Then we have to append the new element to the &lt;span class="caps"&gt;DOM&lt;/span&gt;. Remember, what we&amp;#8217;re appending here is really just some more JavaScript that we&amp;#8217;ll use to alter the page contents. Here&amp;#8217;s the code in that &lt;span class="caps"&gt;RJS&lt;/span&gt; template again (add.rjs), as a reminder:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;page.replace_html 'hello_msg', @thing[:name]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alright, that&amp;#8217;s great. But what does the JavaScript code look like that actually gets generated?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;try {
  Element.update("hello_msg", "Welcome Interstate Managers");
} catch (e) { 
  alert('RJS error:\n\n' + e.toString()); alert('Element.update(\"hello_msg\", \"sdafdsfsdff\");'); throw e 
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That Element.update instruction is Prototype&amp;#8217;s way of saying &amp;#8220;take the &lt;span class="caps"&gt;DIV&lt;/span&gt; identified as &lt;i&gt;hello_msg&lt;/i&gt; and replace it&amp;#8217;s guts with the string &lt;i&gt;Welcome Interstate Managers&lt;/i&gt;&amp;#8221;. Of course, that&amp;#8217;s just the string we gave it when we serialized our form data and sent it off (see previous article for details). Simple but powerful.&lt;/p&gt;
&lt;p&gt;OK so that rocks, but there&amp;#8217;s a bit of redundancy here. Yahoo&amp;#8217;s Connection Manager utility and Prototype do a lot of the same stuff. That duplication is totally against the &lt;span class="caps"&gt;DRY&lt;/span&gt; spirit we&amp;#8217;re going for. Sigh. Now I&amp;#8217;m not well versed enough in the finer details to advocate The One True Way here, but I should note that I&amp;#8217;m much more experienced with Prototype than I am with the &lt;span class="caps"&gt;YUI&lt;/span&gt; connection manager. Prototype is also much more entrenched in Rails, serving as the basis for both Scriptaculous and &lt;span class="caps"&gt;RJS&lt;/span&gt;, and it looks to remain that way as Sam Stephenson (Prototype&amp;#8217;s creator) is part of the Rails core team.&lt;/p&gt;
&lt;p&gt;Anyway, the point I&amp;#8217;m trying to make is that the Yahoo UI connection manager library adds further unnecessary bloat to our applications, since it&amp;#8217;s essentially just replicating what Prototype already does. I&amp;#8217;m sure the &lt;span class="caps"&gt;YUI&lt;/span&gt; guys have their reasons for re-implementing this stuff (Prototype isn&amp;#8217;t universally well-loved), but it&amp;#8217;s kind of unfortunate for Rails developers, who are pretty well married to Prototype at this point. That isn&amp;#8217;t to say that the Yahoo stuff is better or worse.&lt;/p&gt;
&lt;p&gt;In the meantime, if we want to use YUI&amp;#8217;s widgets, we just have to suck it up and eat a little extra pie this holiday season. Maybe it&amp;#8217;s worth writing an alternative connection.js to act as a Prototype wrapper. Maybe we could whip up some helper modules to get these excellent UI widgets as well integrated into the Rails framework as the Scriptaculous stuff is. I&amp;#8217;m sure this is all very possible, but just need to spend some time digging through the stuff in more detail. In any case, it seems clear that proper RoR integration needs a bit more thought. Add it to the &lt;span class="caps"&gt;TODO&lt;/span&gt; list!&lt;/p&gt;
&lt;p&gt;PS the folks at &lt;a href="http://openrico.org/"&gt;OpenRico&lt;/a&gt; have done a nice job providing a set of controls that are very RoR-friendly. Their focus is somewhat different than that of the Yahoo library, more emphasis on behaviors and cinematic effects rather than on widgets, per se. They have a great accordion widget though, and a live grid too (although it currently lacks cell editing support, which is one of the key things we&amp;#8217;re looking for).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>YUI Dialog On Rails: First Pass</title>
   <link href="http://blog.zerosum.org/2006/11/18/yui-dialog-on-rails-first-pass.html" />
   <published>2006-11-18T00:00:00-05:00</published>
   <updated>2006-11-18T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2006/11/18/yui-dialog-on-rails-first-pass</id>
   <content type="html">&lt;p&gt;RoR seamlessly integrates with Prototype and the &lt;a href="http://script.aculo.us/"&gt;Scriptaculous&lt;/a&gt; library, buying us slick auto-complete fields, sortable lists, some nifty effects and all sorts of other web2.0-ish goodies. But when it comes to more advanced UI toolkit widgets, ones you&amp;#8217;d find in desktop app frameworks, like draggable modal dialogs, tabbed panels, and active data grids, it seems hard to beat the library that Yahoo has put together. [That is, unless you want to start mucking with Adobe&amp;#8217;s Flex. But that&amp;#8217;s a topic for another conversation&amp;#8230;]&lt;/p&gt;
&lt;p&gt;The &lt;a href="http://developer.yahoo.com/yui/"&gt;Yahoo UI Library&lt;/a&gt; has been around for a while now (since February) and I&amp;#8217;m just now getting around to playing with it. Unfortunately, there&amp;#8217;s no Rails helper module or anything of that sort. But that doesn&amp;#8217;t mean we can&amp;#8217;t build one ourselves, or at least make them play nice together&amp;#8230;&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s start with something simple. Oh yeah, I should mention that &lt;a href="http://sonjayatandon.com/07-2006/how-to-get-rails-and-the-yahoo-user-interface-yui-to-talk-part-1/"&gt;Sonjaya Tandon&lt;/a&gt; covered this same sorta stuff and what I&amp;#8217;m doing is based on what I found there, but I&amp;#8217;m going to do it a little bit differently, and demonstrate how you can leverage &lt;span class="caps"&gt;RJS&lt;/span&gt;. Here we go:&lt;/p&gt;
&lt;p&gt;First, let&amp;#8217;s set up a Rails project and create a controller. Call it ExampleController:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class ExampleController &amp;lt; ApplicationController
  layout "standard", :except =&amp;gt; :add&lt;/code&gt;

&lt;code&gt;  def show
  end&lt;/code&gt;

&lt;code&gt;  def add
    @thing = params[:thing]
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty simple stuff. We&amp;#8217;ll need an &lt;span class="caps"&gt;RHTML&lt;/span&gt; view template for the &lt;i&gt;show&lt;/i&gt; action, and an &lt;span class="caps"&gt;RJS&lt;/span&gt; template for our &lt;i&gt;add&lt;/i&gt; action. We&amp;#8217;ll also need a layout that&amp;#8217;ll be added to everything but our add action. Let&amp;#8217;s take a look at that layout (standard.rhtml):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;title&amp;gt;YUI Tester: &amp;lt;%= controller.action_name %&amp;gt;&amp;lt;/title&amp;gt;
  &amp;lt;%= javascript_include_tag :defaults %&amp;gt;
  &amp;lt;%= javascript_include_tag "yui/yahoo", "yui/dom", "yui/event", "yui/connection", "yui/dragdrop", "yui/container" %&amp;gt;
  &amp;lt;%= stylesheet_link_tag  'yui/container'%&amp;gt;
  &amp;lt;script language="javascript"&amp;gt;
    YAHOO.namespace('yuitest');&lt;/code&gt;

&lt;code&gt;    function initDialog() {
      var handleCancel = function() {
        this.cancel();
      }&lt;/code&gt;

&lt;code&gt;      var handleSubmit = function() {
        //this.submit();
        new Ajax.Request('/example/add', {asynchronous:true, evalScripts:true, parameters:Form.serialize(myDialogForm)});
        this.hide();
      }&lt;/code&gt;

&lt;code&gt;      YAHOO.yuitest.myDialog = new YAHOO.widget.Dialog("dlg", {
        width: "500px",
        modal: true, 
        visible: false,
        fixedcenter: true, 
        constraintoviewport: true, 
        draggable: true });&lt;/code&gt;

&lt;code&gt;      var myButtons = [ { text: "Save", handler: handleSubmit, isDefault: true },
        { text: "Cancel", handler: handleCancel } ];    
      YAHOO.yuitest.myDialog.cfg.queueProperty("buttons", myButtons);
      YAHOO.yuitest.myDialog.render();
    }&lt;/code&gt;

&lt;code&gt;    function addThing() {
      document.myDialogForm.thing_name.value = "";
      YAHOO.yuitest.myDialog.show();
    }&lt;/code&gt;

&lt;code&gt;    YAHOO.util.Event.addListener(window, "load", initDialog);
  &amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;div id="main"&amp;gt;
    &amp;lt;%= @content_for_layout %&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So there&amp;#8217;s a bunch of JavaScript in there. I&amp;#8217;m going to work on cleaning all that up and building a helper module later but for now let&amp;#8217;s just get something functional.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ve copied the relevant &lt;span class="caps"&gt;YUI&lt;/span&gt; library javascripts to our public/javascripts directory, and now we include them in the layout along with our defaults (prototype, etc). We&amp;#8217;d want to trim this down to just what we need before deploying an app for real world use of course.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;re going to create a dialog from the &lt;span class="caps"&gt;YUI&lt;/span&gt; and add two buttons on it (save, cancel) and the corresponding event handlers. We also need to add a function addthing() that will be called when the user clicks on the link in the show template. It will simply reveal our modal dialog. If you&amp;#8217;re confused about any of the syntax here, see the &lt;span class="caps"&gt;YUI&lt;/span&gt; docs and tutorials. Lots of good stuff over there, extremely well documented.&lt;/p&gt;
&lt;p&gt;Now here&amp;#8217;s our show template (show.rhtml):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div name="hello_msg" id="hello_msg"&amp;gt;hello&amp;lt;/div&amp;gt;&amp;lt;br /&amp;gt;
&amp;lt;a href="#" onclick="addThing()"&amp;gt;Add Thing&amp;lt;/a&amp;gt;
&amp;lt;!-- begin: dialog box --&amp;gt;
&amp;lt;div id="dlg"&amp;gt;
  &amp;lt;div class="hd"&amp;gt;this is a dialog&amp;lt;/div&amp;gt;
  &amp;lt;div class="bd"&amp;gt;
    &amp;lt;%= form_tag({:action =&amp;gt; :add}, {:name =&amp;gt; 'myDialogForm'}) %&amp;gt;
      &amp;lt;label for="thing_name"&amp;gt;Thing Name:&amp;lt;/label&amp;gt; &amp;lt;%= text_field('thing', 'name') %&amp;gt;
    &amp;lt;%= end_form_tag %&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;!-- end: dialog box --&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the form name (myDialogForm) must match up. Also note that the dlg &lt;span class="caps"&gt;DIV&lt;/span&gt; uses the same name we initialize the dialog to in the layout. This is important, it means the contents of this div are rendered within the modal dialog and are therefore hidden from the view by default. When you click on the &amp;#8216;Add Something&amp;#8217; link, the dialog will pop up. You&amp;#8217;ll be able to drag it around the screen and enter some text in it. Yay. Then you can click save, and it should update the hello_msg &lt;span class="caps"&gt;DIV&lt;/span&gt;. There&amp;#8217;s an easier way to do this of course, but we&amp;#8217;re going to use &lt;span class="caps"&gt;RJS&lt;/span&gt; because the approach is demonstrative of a lot more powerful stuff you can do, leveraging Rails model data you may have on the backend and perhaps doing some processing or database access before rendering the results. You get the idea.&lt;/p&gt;
&lt;p&gt;So when you hit that save button, the code in the submit handler is run. Let&amp;#8217;s look at that JavaScript again:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;new Ajax.Request('/example/add', {asynchronous:true, evalScripts:true, parameters:Form.serialize(myDialogForm)});
this.hide();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We serialize the data in the form (that one text field) and submit the data asynchronously by making a direct call to Ajax.Request (thanks Prototype!). Then we hide the model dialog again, returning control to the main page. Notice that &lt;span class="caps"&gt;URL&lt;/span&gt;: &lt;i&gt;/example/add&lt;/i&gt;. This calls the &lt;i&gt;add&lt;/i&gt; action on our ExampleController, which does something important &amp;#8212; in theory &amp;#8212; and then renders out an &lt;span class="caps"&gt;RJS&lt;/span&gt; template. This &lt;span class="caps"&gt;RJS&lt;/span&gt; template, for our simple example, just replaces the hello_msg div&amp;#8217;s inner &lt;span class="caps"&gt;HTML&lt;/span&gt; with whatever it was we typed into that text field. Here&amp;#8217;s the &lt;span class="caps"&gt;RJS&lt;/span&gt; template, add.rjs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;page.replace_html 'hello_msg', @thing[:name]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#8217;s it for now! We&amp;#8217;ll revisit this later if I have time, and try to figure out how to wrap it up in a module to make it easier to use and more general purpose.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>Down w/ with_scope</title>
   <link href="http://blog.zerosum.org/2006/11/8/down-with-with_scope.html" />
   <published>2006-11-08T00:00:00-05:00</published>
   <updated>2006-11-08T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2006/11/8/down-with-with_scope</id>
   <content type="html">&lt;p&gt;We need to delete some stuff. But when we delete items, we don&amp;#8217;t &lt;b&gt;really&lt;/b&gt; delete them because hey, we don&amp;#8217;t have to (we might want them later, no?) So we have an attribute on the model, &lt;i&gt;deleted&lt;/i&gt;, which is null if the item is current. When we delete an item, we update_attributes to set deleted to the current datetime.&lt;/p&gt;
&lt;p&gt;Yes, yes, I know, this is really common stuff. But hold on, this is where it gets kind of interesting. We want to call find on the model, like always, and only get back current items that have not been deleted. Oh, and we don&amp;#8217;t want to have to pass in the condition every time, because that&amp;#8217;s just gross. We&amp;#8217;d just like to, well, add the condition to the scope. This is where the magic of &lt;a href="http://api.rubyonrails.com/classes/ActiveRecord/Base.html#M000892"&gt;with_scope&lt;/a&gt; can help us out.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s declare a method find_current on the model:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def self.find_current
  find(:all, :conditions =&amp;gt; "deleted IS NULL")
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well that works for our base case (finding all current items) but it&amp;#8217;s pretty inflexible. What if I want to pass in an ID, specify a limit, additional conditions, etc?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def self.find_current(*args)
  with_scope(:find =&amp;gt; { :conditions =&amp;gt; "deleted IS NULL" }) do
    find(*args)
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The answer is to use with_scope, which allows us to specify conditions here that will apply throughout the course of the block. Now we can do things like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Item.find_current(:all, :limit =&amp;gt; 10)
Item.find_current(:first, :conditions =&amp;gt; "name LIKE '%perishable%'")
Item.find_current(13)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which invoke the find_current method on the model with our additional parameters and includes our deleted condition in the scope automatically.&lt;/p&gt;
&lt;p&gt;K, so still not exactly rocket science, but it is a nice, clean solution to a common issue for sure. Unfortunately, with_scope isn&amp;#8217;t found in my copy of Agile Web Development with Rails, which is my main reason for noting it here. Hopefully it&amp;#8217;ll be in v2! Some other helpful bloggers are out there though, check out &lt;a href="http://www.ryandaigle.com/articles/2006/07/20/a-rails-feature-you-should-be-using-with_scope"&gt;Ryan Daigle&amp;#8217;s blog&lt;/a&gt;, which is where Ian found the article that got us started on this path.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <author>
     <name>Nick Plante</name>
   </author>
   <title>In My Younger And More Vulnerable Years...</title>
   <link href="http://blog.zerosum.org/2006/11/4/in-my-younger-and-more-vulnerable-years.html" />
   <published>2006-11-04T00:00:00-05:00</published>
   <updated>2006-11-04T00:00:00-05:00</updated>
   <id>http://blog.zerosum.org/2006/11/4/in-my-younger-and-more-vulnerable-years</id>
   <content type="html">&lt;p&gt;Thus began the Zerosum dev blog, a place for folks who work on our code to muse about daily development happenings and such.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve never been one to keep a blog, personally, but I think of this area as a useful place for us to post about things that don&amp;#8217;t belong in our project trac wiki or elsewhere. Things you want to share with others. Things like: &amp;#8220;Wow cool, Ian found a new way to do X that totally rocks. Spread the word&amp;#8221; and &amp;#8220;Rails migrations rule, check out this snippet!&amp;#8221;, and &amp;#8220;Saw this thing on Foo&amp;#8217;s blog about how to do Y without needing Z. Maybe we should think about refactoring the BlahController to do that too?&amp;#8221;&lt;/p&gt;
&lt;p&gt;You get the idea.&lt;/p&gt;</content>
 </entry>
 
</feed>
