taylorbarstow.com

The Ruby Community Rocks

The acts_as_rated plugin (see also: rdoc, github) just saved me hours of work.  Ruby is a (really, really) great language and Rails is a great framework, but I’m quickly realizing that the Ruby and Rails communities are more valuable than either of those two points.  There is a true spirit of sharing.  Everyone is working on their own projects, but they always seem to pull out the really useful bits and publish them as gems or as Rails plugins.  To me, this is what open source is all about.

I’m not 100% sure why this community seems so much more enthusiastic about sharing than other language or framework oriented communities, but I do have some ideas.  Maybe I’ll explore that later.

Careful With Those Migrations!

I’m usually really careful with Rails migrations.  At a previous job I implemented a home-spun build system which included a migration-like feature. That experience gave me a lot of insight into how fragile migrations can be.

Well, today I ran into my first migration problem in some time. On Friday, I started implementing a major new feature of the project I’m working on. Like a good little programmer, I created a branch in my versioning tool of choice (git).

Today, I came back from a long weekend and hadn’t finished that feature. I needed to wait to talk to Adrian a bit before going ahead, so I decided to work on a couple of small problems instead. I switched back to my main branch, implemented the small stuff, and pushed it live (we’re still in alpha here, so I push pretty often).

A couple of hours ago I finally got that conversation with Adrian in, finished off Friday’s feature, and merged it back into the main branch. I thought the merge would be smooth but I got a conflict. No big deal, I thought, until I saw where the conflict was: in schema.rb. The conflicting line was the schema version.

Oh, no big deal (I thought again) it’s just because I haven’t migrated up my main branch. So I fixed the conflict, ran my migrations, and (like a good little programmer) kicked off my unit tests.

FAIL

Uh-oh. WTF!? Confusion and frustration, all at the same time. It appeared one of my tables from Friday’s big-feature-branch didn’t exist in my database. Then it dawned on me. I had inadvertently applied migrations out of order. You see, my minor changes this morning had minor migrations associated with them. So that table I added on Friday got lost. And I didn’t even notice, because I was working in isolated branches!

There are a few ways you can fix something like this - I opted for using rake to roll the database schema back to the last known good version, then migrate up from there. This worked on development and in production, because (as I said) we are in alpha mode here, so a little downtime is OK (it took literally 30 seconds). But if we were in beta or production mode, I would have been in trouble.

Moral is, watch out for those migrations - especially when branches are involved! They are pretty easy to screw up.

Rails: Augmenting ActiveRecord::Base#find

Let’s say you want to modify a given ActiveRecord class such that all #find calls will, by default, sort by a given column. I ran into this the other day, and I wasn’t quite sure how to do it. Turns out it’s actually pretty easy (though not 100% trivial for the noob):

class User < ActiveRecord::Base
  def self.find(*args)
    options = args.extract_options!
    options[:order] ||= "last_name ASC, first_name ASC"
    super(*args.push(options))
  end
end

This snippet will cause User#find calls to by default sort the results first by last_name, then by first_name. If, however, you specify the :order option when calling #find, this method will respect your choice.

Caveat: I’m not sure when Array#extract_options! showed up in Rails’ ActiveSupport library, but it’s at least there as of 2.1.0.

Ruby: HTTPClient is Sloooooow

Is this just me? I think it must be—I am getting terrible performance using HTTPClient vs Net::HTTP. I was looking for an alternative to Net::HTTP because its API is ugly as hell, but the performance difference leaves me with no choice.

Let’s take the example of loading this blog’s last four entries using the Google AJAX Feed API. Net::HTTP consistently takes less than a second to load the results, while HTTPClient consistently takes between 10 and 15 seconds! This can’t be right, I must be doing something wrong…

Here’s the script I’m using to test:

require 'httpclient'
require 'net/http'
require 'uri'
require 'cgi'

def time(label)
  t_start = Time.now.to_f
  yield if block_given?
  puts "#{label}: #{Time.now.to_f - t_start}s"
end

feed_url = "http://taylorbarstow.com/feed/"
url = "http://www.google.com/uds/Gfeeds?v=1.0&amp;amp;amp;output=json&amp;amp;amp;q=#{CGI.escape(feed_url)}"

time "Net::HTTP" do
  Net::HTTP.get(URI.parse(url))
end

time "HTTPClient" do
  HTTPClient.new.get_content(url)
end

Typing Furiously

That would be the caption on a photograph of me when I’m at my best (professionally speaking, that is).  Finally, this happened to me today while using Cocoa!

This is exciting.  It means that instead of stopping to be confused, now I can stop to think things through.  Instead of stumbling over new API’s and design patterns, now I can hold my program in my head.  In short, I can program effectively in my new environment.

Watch out!  As of today, we’re cooking with gas.

Oh, and I redesigned my blog, too.