Gravatar default images - a better way

Posted on January 26, 2010

Hey, so at Harmonypark we decided to put gravatars into one of our applications (which is so easy it’s not funny) – and when the time came to select the default images for the gravatar I piped up: “I know how to fix this!” and pointed to a blog post I wrote about it long ago: (You can read it here.)

My colleague Ebony came up with a great solution: “Why not use another gravatar as the default image.”

Which is an utterly brilliant idea – that way the default image gravatar will scale correctly, and we wouldn’t have to mess around with having different image sizes for the different scaled default images. Here’s how we did it:

1) Go to gravatar.com and add a default gravatar for some email address that you won’t use.

2) Install the gravatar plugin
script/install http://github.com/woods/gravatar-plugin/

3) Extend the gravatar plugin to allow for a default email address by putting this code in lib/gravatar_extension.rb (remember to include this file in a initializer).

module GravatarHelper  
  module PublicMethods  

    def gravatar_for_with_default(object, options={})
      options.merge!(:default => gravatar_url("your-default-email@example.com", options))
      gravatar_for_without_default(object, options)  
    end  
    alias_method_chain :gravatar_for, :default  
  end  
end

4) Now, everytime a user is missing a gravatar, the default image will be your default gravatar, this will handle all the awesome scaling stuff that gravatar does too

What columns does an ActiveRecord model have?

Posted on April 20, 2009

Something that bugs me about using ActiveRecord models is that I have to look in schema.rb file to remember what columns a model has.

Enter…What Column!

This is a little plugin I bunged together on the (long) train journey home from Scotland on Rails.

What it does is put a comment block in all of your ActiveRecord models detailing what columns this model has. The beauty is that it changes every time you run rake db:migrate in development mode – so once it’s installed it will always be up to date. Your models will now look like this:

class User < ActiveRecord::Base

  # === List of columns ===
  #   id         : integer 
  #   name       : string 
  #   created_at : datetime 
  #   updated_at : datetime 
  # =======================

end

Source code here:

http://github.com/thechrisoshow/what_column/

Installation

Install it like this:

script/plugin install git://github.com/thechrisoshow/what_column.git

After you’ve installed it run this rake task to create the initial comment blocks.

rake what_column:add

Every time you run rake db:migrate from then on the comment blocks will be updated.

Uninstallation

If you get sick of What Column, and you want to uninstall it do this:

Run rake what:column:remove

Delete the plugin from the vendor/plugins/what_column directory

Warning

This file writes stuff into your model files, and it may destroy stuff. So make sure you use a source control system – you know, just in case.

Refactor away your comments

Posted on February 22, 2009

Last week I had the good fortune of having my colleague Abdel Saleh go through some rspec specs I had written.

“Why do you need this comment?” he asked for a bit of code like this:
before(:all) do 
  # Ensure doesn't actually save to Mogile FS
  MogileFS::MogileFS.any_instance.stubs(:store_content)
end
..and he promptly deleted it..

“No wait!” I said defensively, “That’s there to prevent the tests from actually hitting mogilefs. The comment’s there because the line of code doesn’t describe the intent”

“Well, that’s easily fixed” says Abdel, “Rather than using a comment to describe the intent, put it in a method with a name that describes the intent.”

before(:all) do 
  ensure_doesnt_save_to_mogile_fs
end

def ensure_doesnt_save_to_mogile_fs
  MogileFS::MogileFS.any_instance.stubs(:store_content)
end

Why is this better!??

Comments aren’t maintainable. They don’t grow and change with the codebase. They lay still and live on like strange messages from ancient civilisations.

In the preceding example you no longer NEED a comment to describe the intent of your code, your code does it for you!

Prefer Guard Clauses over nested conditionals

Posted on February 16, 2009
Ever find yourself wrapping a method with a conditional:
  def save_to_file(filename)
    unless filename.blank?
      do_something
      do_something_else
    end
  end

Or maybe you subscribe to the one exit from a method strategy.

I write code that looks like this a lot. And you know what, I didn’t think it had a code smell until my colleague Abdel looked over it the other day.

“Why don’t you ever use guard clauses?” he asked.

A guard clause is a conditional statement at the top of a function that bails out as soon as it can. Like this:
def save_to_file(filename)
  return false if filename.blank? #<- Guard clause

  do_something
  do_something_else
  File.write...# blah blah
end

I didn’t have a good reason for not using Guard Clauses, except an idea in the back of my head that there should only be one exit from a method. There’s a bunch of stuff online that promotes this way of writing methods, but I’ve discovered recently that most of the reasons to support one exit are baloney.

Functions with single exit points are handy for languages that require decent memory management like C, but in Ruby where you have a garbage collector this doesn’t make any sense.

Also, if you’re writing uber long functions, then it makes sense to have a single exit point – but if you’re writing uber long functions then you’re a terrible programmer.

Anyway, so Abdel refactored my code by adding in some tasty guard clauses, and I’ve become a die hard fan.

PS: Of course, with all refactoring it’s about the readability and maintainability of your code. Don’t blindly adopt guard clauses if it makes your code harder to read.

PPS: Read more about guard clauses at refactoring.com

Localizing your Rails application

Posted on December 11, 2008
I wrote a better version of this article for the Ruby Advent 2008 site. Find it here: http://advent2008.hackruby.com/past/2008/12/16/rails_22_internationalization/

Recently I discovered that most of the visitors to one of my apps (What I want for Xmas) were from Italy. It suddenly seemed like a good time to localize my Rails application, but I had no idea where to start! I asked my twitter stream for recommendations for a good Rails plugin.

Peter Cooper pointed me in the right direction:

Peter Cooper sets me straight

Yep! Rails 2.2 includes nice localization stuff right out of the box!

So, after some hard work I localized my app to cater for Italian visitors. (You can check out the Italian version here).

Here’s how I did it:

Get your Rails app ready for localization

In Rails 2.2 you get a folder that keeps all your locale details: /config/locales. This is where you’ll keep all the different locale snippets in files named after the locales (en.yml, it.yml etc)

You can set the default locale by setting a flag in environment.rb:
      config.i18n.default_locale = :en

Translate your application into English

Next (oddly enough) you’ll need to translate your application into English (or whatever language your app is already). This means finding all the places where you have fragments of English and replacing it with something that looks like this:

t("main.title")
The t* stands for translate, and *main.title refers to a key in the locale yaml files. The yaml file can have nested keys, so, “main.title” finds the title key belonging to the main key in the yaml file. e.g.
    main:
        title: "Some title" 
You can use string interpolation as well. So if you have text that looks like this:
    "What #{name} wants for Xmas" 
You can simply put the name of the variable within double braces in the yaml line like so:
    title: "What {{name}} wants for Xmas" 
And then call on it with the t method by passing in the variable. Like this:
    t("title", :name => user.first_name)

Translate your application into other languages

After you’ve gone through the arduous process of translating your app to English (yawn!) you can then create translations into other languages!

What I did was just grab the yaml file, and send it to an Italian friend to translate.

Here’s a portion of an example English yaml file:
en:
  main_title: "What I want for Xmas" 
  countdown:
    merry_xmas: "Merry Christmas!" 
    days_until_xmas: "Only {{number_of_days}} until Xmas" 
    days: "days" 
    day: "day" 
And here’s the translated version:
it:
  main_title: "Ciò che voglio per Natale!" 
  countdown:
    merry_xmas: "Buon Natale!" 
    days_until_xmas: "Solo {{number_of_days}} fino a Natale" 
    days: "giorni" 
    day: "giorno" 

Provide a way to switch between different locales

So, now you’ll need to add the ability to switch locales. What I did was put a before_filter in application.rb that sets the locale depending on:
  • whether the user is logged in and has a locale
  • whether the locale is stored in the session
  • failing that, use the default_locale – although this step could be unnecessary, but makes me feel comfortable.
    # in Application.rb
    before_filter :set_locale  

    def set_locale
        I18n.locale = (current_user.locale if current_user) || session[:locale] || I18n.default_locale
    end
I also included a locales controller for switching locality.
# locales_controller.rb
class LocalesController < ApplicationController  
  def show
    if current_user # if I'm logged in
      current_user.locale = params[:locale] # change my locality
      current_user.save
    end        
        session[:locale] = params[:locale]               

    redirect_to :back
  end
end

# routes.rb

  map.locales 'locales/:locale', :controller => 'locales', :action => 'show'
This enabled me to have links for simply switching languages that look like this:
    link_to "English", locales_path('en')

Tips

Localizing your app can be a frustrating experience. Here’s some tips to ease the pain:

Repeat yourself

Resist the urge to DRY up your yaml snippets and have them used in several different locations. Different languages could translate your snippets differently depending on context.

Provide context for your translators

Your translators need to know a little bit about the context that the text represents. Write comments in your yaml file to make it easier for them.

Avoid the pluralize method

Right now, you can’t trust the pluralize helper method if you’re using localization. (i.e. it tried to say that the plural of giorno (day) is giornos (it’s actually giorni) Instead, provide keys in your translation yaml files asking for the plural and singular words, and write a method for dealing with the plural.

Adopt some sort of convention in your yaml files for links that are embedded in other text.

For example, if you wanted to write Sign up if you want to join whatiwantforxmas.com I would separate this out in the yaml file like this:
    sign_up: "{{link}} if you want to join whatiwantforxmas.com" 
    sign_up_link: "Sign up" # this is the text used in the 'link' variable above

Just because the “Sign up” appears at the front of the sentence in English, doesn’t make it so in another language.

Remember ActiveRecord validation messages and dates

Rails includes numerous English phrases. You can translate this quite easily by including the sample code found here in your yaml files.

What’s this Yaml thing?

Ideally you’ll want to get your translators to translate the yaml file. Beware though that yaml is a strange file format to non-technical people. Let your translators know here do get a file editor that they can use (SciTE for example. Grab it at http://prdownloads.sourceforge.net/scintilla/Sc177.exe)

But is it REALLY right

After getting the translation, walk through the website with the translator to make sure it’s REALLY right. Sometimes things translate differently when the context changes. I also noticed that some special characters sometimes got mixed up, so this is a good opportunity to spot those.

Translate ALL of the snippets

As I write this, if any of your translation files are missing a snippet, then you’ll get nasty ‘span’ classes outputted onto the screen. Make sure that each and everyone of your snippets are updated in every locale yaml file.

Add Gravatars to your Rails Application

Posted on October 27, 2008

I wanted to add Avatars to my new project whatiwantforxmas.com but it felt like too much hard work. So, I took a leaf out of githubs book and used Gravatars.

Gravatars are an already pre-packaged avatar system, all bright and shiny and ready to be added to your application.

If you haven’t got a Gravatar do me a favour, go over to gravatar.com and signup

It’s ridiculously easy to put in your app!

I use Scott Woods nice little Gravatar plugin – you can install it in your Rails app thusly:
script/plugin install svn://rubyforge.org/var/svn/gravatarplugin/plugins/gravatar
Here’s how you use it, bung this into your view (where user is an object that has an email attribute):
gravatar_for(user)

And BOO YA – you’ve got an instant gravatar image on your page!

You could also call by passing in an email address (but it’s not so sexy):
gravatar(user.email)
gravatar("jim@banana.com")
You can even set which size you want! (As in this case 50px x 50px)
gravatar(user.email, :size => 50)

“But wait! What if the user doesn’t HAVE a Gravatar?!” Well, then a default image is used instead. Typically something nasty like this:

But dry your eyes, all is not lost. You can set your own default Gravatar! When you call the Gravatar method just pass in a :default param pointing to the default image you want to use.
gravatar_for(user, :size => 50, :default => "http://www.whatiwantforxmas.com/images/avatars/santa/santa-50.png")

I wasn’t into the scaling of the default images though, so I wrote this little snippet of code so that you can have a separate default image for each Gravatar size you want. This ensures that I only use Gravatars that are 25, 50 or 70px (the sizes that I have default images for).

Copy this code into a file in your lib folder, and don’t forget to ‘require’ it in an initializer.

module GravatarHelper
  module PublicMethods

    AVATAR_SIZES = [25, 50, 70]

    def gravatar_for_with_default(object, options={})
      options[:size] ||= 25      
      options.merge!(:default => "http://www.whatiwantforxmas.com/images/avatars/santa/santa-#{options[:size]}.png")      
      # sizes are 25, 50 and 70
      raise RuntimeError, "Incorrect size for Avatar" unless AVATAR_SIZES.index(options[:size])    
      gravatar_for_without_default(object, options)
    end
    alias_method_chain :gravatar_for, :default
  end
end
And then I just need to call it like this:
gravatar_for(user, :size => 50) # This will use my default avatar

PS Yeah, I know I know – my blog doesn’t use Gravatars yet…

A peek at the inner workings of Hashrocket

Posted on October 02, 2008

Recently the folk over at Hashrocket had another one of their famed 3-2-1 Launches - this time inviting as guest stars Tammer Saleh and Joe Ferris of another renowned Rails shop Thoughtbot. The application they worked on is called spot.us and is a community funded reporting tool.

The interesting thing about this project was that the source is freely available on Github for any Joe Bloggs to pour over (link). Not only that, but the client taped his reaction upon seeing the application for the first time: (link).

I had a quick looksee at the application, and what I saw blew me away - how'd they get so much done in such a short space of time?

Here's some of the stuff I noticed:

Used a good amount of boilerplate

Let's face it, a good chunk of every application is the same as the last application. Hashrocket have got a pretty decent suite of boilerplate code that they bung into the app to get started.

Upfront design

The week before the sprint, a bunch of stuff was checked in to do with user interface. this included:

  • Mocked up views,
  • All the images necessary for the design,
  • Javascript plugins

Basically, a good solid structure was in place so that the developers could go hard on concentrating on what they need to do, and not worry about big design decisions.

Not only that, but before any work had done, the application ''looked'' just like the final product, even if it didn't necessarily work yet.

Uber frequent commits

Take a look at the github network tree on the 24th, 25th and 26th - every 6 or so minutes something gets checked in. These folks checked in so fast it was as if their lives depended on it.

This is because they had small, perfectly formed units of work. Get the issue, work on it, check it in -> rinse and repeat. Also because of the hard-core frequent commits there were only 2 source code conflicts for the entire stretch!

Haml

I've studiously avoided haml throughout my Rails career because a niggling sensation at the back of my head doesn't feel comfortable with adding another layer of abstraction between me and the html. I've been bitten before with all the asp.net stuff Microsoft uses to hide html from .NET developers - and have since loved looking at plain old html since.

In spot-us all of the views are done in HAML.

After reading it for a bit, and getting my head around all that white space, I realised that the intent of the code was really easy to comprehend - I didn't have to wade through all that excess html junk we put up with. Instead the templates read like a page of code, filled with lovely methods and variables.

Used JQuery AND NOT Prototype

So, there's a weird little nasty part of me that believes you have to take sides in the great Javascript Framework War. Historically Rails developers belong to the Prototype/Scriptaculous faction - but all the hip cool kids these days seem to be gravitating towards JQuery.

Hashrocket instead decided to go with the best bits of both worlds by implementing bits of each. In their code you can see the old glory (some would say divisive) use of remote_form_for (which generates prototype Javascript) combined with the new hotness of JQuery plugins.

UPDATE Thanks to Ben Scofield for pointing out in the comments that the Hashrocket team actually use the jRails plugin. This plugin ensures that all the Rails javascript helper methods spit out JQuery rather than Prototype/Scriptaculous code. Find out more here.

JQuery has a nice little method:

jQuery.noConflict( );

This helps to make sure that jQuery doesn't conflict with other libraries - pretty sweet.

Done away with fixtures and used factory_girl

The Geniuses (Geni-i?) at Thoughtbot forego the whole fixtures route in favour of creating custom factories for their tests. The sweet little plugin that enables all this magic is called Factory Girl.

Here's an example - instead of calling out to a donation fixture, they just create a factory of a couple and populate it with the relevant attrbutes.

it "isn't valid if there is already a donation for that tip and user" do
  donation = Factory(:donation)
  duplicate = Factory.build(:donation, :pitch => donation.pitch, :user => donation.user)
  duplicate.should_not be_valid
  duplicate.should have(1).error_on(:pitch_id)
end

I'm not sure if Hashrocket started using factory_girl in this project because of their special guest stars, but it's not part of the standard boilerplate code.

Rspec view tests

Something hot and juicy about the hashrocket test suite was the inclusion of View Specs. RSpec view tests allow you to set expectations of your views in a nice sweet fashion without having to worry about the whole http round trip business.

For example:

describe 'profiles/show' do

  include ActionView::Helpers::AssetTagHelper

  before do
    assigns[:profile] = Factory(:user)
  end

  it "should display a thumbnail when available" do
    url = '/url/to/file.jpg'
    attachment = mock('attachment', :url => url)
    assigns[:profile].stub!(:photo).and_return(attachment)
    do_render
    response.should have_tag('img[src = ?]', url)
  end
end

Look ma, no controller!

Launch party

After a 3-2-1 Launch the hashrocket guys 'n' gals have an awesome big party. Judging from the tweets, it sounded like a fun time was had by all.

It got me thinking, most projects I've worked on don't specifically have an end point - they just kinda keep on going until they peter out and another project shows up. Having a definite line in the sand is a great motivating factor.

And finally

There's still a bunch of fiddly stuff to do on spot-us - but it's pretty amazing what they came up with.

Rats off to ya!

Rats off to ya!

Using assert_select on strings

Posted on October 01, 2008

Question:

assert_select is awesome for testing dom objects – but it relies on using the standard rails response cycle. How can I use assert_select on to find dom elements in a standard string?

Answer:

Stub the response object!

def test_big_selector_helper
  # the response requires a content_type - just set it to "text" 
  @response.stubs(:content_type).returns "text" 

  # big_element_selector is the helper method I'm testing in this instance
  # replace with the string that you want to test
  @response.stubs(:body).returns big_element_selector

  # now you can use assert_select
  assert_select "ul" do
    assert_select "li", :count => 3
  end
end

Set the default date format for your Rails application

Posted on September 24, 2008
(Apologies to who I nicked this from – I can’t remember which book or blog post I found this)
The default string format for Dates is the ‘Database’ format which looks like this:
Date.today.to_s => "2008-09-24" 

So, this means if you have dates in your views they’ll default to that unless you force the format.

It’s really easy to set the default format though! Bung something like this in your environment.rb:

  ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.merge!(
  :default => '%d %B %Y' )  

Where :default is the format you want to set. Now your dates will automatically default to a nice format!

Date.today.to_s => "24 September 2008" 

You can do the same with the time format:

  ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
  :default => '%d %B %Y'
  )  

Display your KML on a Google Map (again) - now using Google App Engine

Posted on May 07, 2008

KML stands for Keyhole Markup Language and is used to create geographically aware information.

It can be tricky to write your own KML by hand- in order to display kml on a Google Map you need to save the markup into a file on a web server that Google has access to. Google then caches this file in it’s own mega-web, so it can take a while for any changes you make to filter through.

My little application fixes these issues by allowing you to paste the kml into a web form, hit a button, and WHAMMO, KML on a Google Map without any of the stupid stuff.

So, almost a year after creating this application with Ruby on Rails I’ve decided to port this little app to use Google App Engine – you shouldn’t notice any difference, but rest assured that it can now scale to support gabillions of visits.

Because everyone’s gonna wanna use it

To try it out by going here and copy and paste the following KML into the box and click the button.
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
  <Placemark>
    <name>Invercargill Rocks!</name>
    <description>Go there and see!</description>
    <Point>
      <coordinates>168.34693908691406,-46.416322245553296,5</coordinates>
    </Point>
  </Placemark>
</kml>

Display KML on a Google Map: http://www.thechrisoshow.com/display_kml

KML Samples

KML Tutorial

KML Reference

PS: Because I rewrote the code in Python it might’ve broken a few things – let me know in the comments if it doesn’t work for you.

Five tips for testing Rails

Posted on May 04, 2008

Tip One – Debugging tests

I use RDebug in my apps a lot, but frequently I found myself wanting to debug my tests. Here’s how you can do it:

If you haven’t done so already, install RDebug
  $ gem install ruby-debug
Insert debugger in your code where you’d like to breakpoint
    def like_bananas?
      # Want to breakpoint here and see what the self.fruit attribute looks like
      debugger
      return self.fruit.likes.include?('bananas')
    end      
And then run the test from the command line using rdebug like this:
    rdebug test/unit/bananas_test.rb

You could even put the debugger reference in your test code as well.

Tip Two – Gently ease yourself into BDD with shoulda

Everybody’s talking about Behaviour Driven Development these days – and the popular BDD tool for Rails is the mighty RSpec.

But, it can seem like quite a bit of a jump to get into RSpec. Maybe you’ve got a well established application with a plethora of Test::Unit tests that you can’t bear to look at. Or maybe you just wanna try out the whole BDD approach for a while and see how it goes without really committing.

Well never fear – there’s a really easy way of easing yourself into BDD and it’s called shoulda. This is a great BDD tool made by the crazy freakin’ geniuses (genii?) over at thoughtbot.

Basically, shoulda is a BDD framework built on top of Test::Unit. It uses all the Test::Unit assertions that we know and love – adds some exotic delicous syntactic BDD sugar – and throws some wonderful helper macros in as freebies..

The thoughtbot folks rabbit on about it over here: http://thoughtbot.com/projects/shoulda.

An example test unit class might look like this:
class FruitBowlTests < Test::Unit::TestCase

  def setup
    @fruit_bowl = get_fruit_bowl
  end

  # Check out this BDD coolness
  should "be best before date" do
    assert @fruit_bowl.fresh?
  end

  # But you can still include old skool tests like this
  def test_fruit_bowl_has_three_fruit
    assert_equal 3, @fruit_bowl.fruit.size
  end

end

So you can try out BDD without messing up your current tests – hooray! Shoulda actually provides way more than this though – but don’t take my word for it, gem install shoulda today!

PS: Not only that, but the shoulda guys include a script that modifies your Test::Unit tests and changes them into shoulda style tests. Run it like this:
 $ ./vendor/plugins/shoulda/bin/convert_to_should_syntax [path to test file]

Tip Three – DRY up your tests with define method

Ever find yourself writing the same tests over and over again but with slightly different modifications – like this:
  def test_banana_should_be_nil_if_fruit_bowl_rotten
    @fruit_bowl = FruitBowl.new(:rotten => true)
    assert_nil @fruit_bowl.banana
  end

  def test_apple_should_be_nil_if_fruit_bowl_rotten
    @fruit_bowl = FruitBowl.new(:rotten => true)
    assert_nil @fruit_bowl.apple
  end

  def test_pear_should_be_nil_if_fruit_bowl_rotten
    @fruit_bowl = FruitBowl.new(:rotten => true)
    assert_nil @fruit_bowl.pear
  end

Using the wonderful Ruby methods define_method and send you can dry this up really easily like thus:

# Put the different bits into an array
[:banana, :apple, :pear].each do |fruit|
  # Iterate over the array and create a test method for each object.  Remember to prefix the method with 'test' when using Test::Unit
    define_method "test_#{fruit}_should_be_nil_if_fruit_bowl_rotten" do
      @fruit_bowl = FruitBowl.new(:rotten => true)
      # And use the send method to check the correct attribute
         assert_nil @fruit_bowl.send(fruit)
    end
  end

Tip Four – Test the objects behaviour

Here’s a tip that should revolutionise your testing methodology forever…

Make sure you test the correct behaviour for an object

What this means is that when testing an object, don’t create a test that looks outside of its scope.

For example:

Up until very recently I used to be a big fixtures man. It wasn’t uncommon for me to write functional tests like this:

    def test_transfers_heading_should_be_on_page
      get :show, :id => festivals(:festival_with_transfers_heading)    
      assert_select 'h3#heading', "Transfers" 
    end

Which was to test that the h3 with the id of ‘heading’ displayed the correct text, in this case “transfers”.

But deep down inside I was relying on this test to do more than what it should be doing. Whenever this test was run it had to load the festival from the database, and show the correct template. However, the scope of the test though was just to test that the correct information was shown in the view, anything else was irrelevant to this test.

A better test could look like this:
    def test_transfers_heading_should_be_on_page
      festival = Festival.new(:heading => 'Transfers')
      Festival.stubs(:find).returns(festival)
      get :show, :id => 1
      assert_select 'h3#heading', "Transfers" 
    end

The database doesn’t get hit because it doesn’t need to get hit. All we’re testing here is that the correct heading is displayed on the page – that the controller fulfilled its obligation by marshalling the data from the model to the view.

Tip Five – Expectations are tests too you know!

Mocks Rock – there I said it!

But, you can get so obsessed with stubbing out all manner of stuff for your assertions that you can mess out on all the nice inbuilt assertions built into mock objects – expectations.

For example, you might have an ActiveRecord observer that does some stuff after a model is saved like this:
  class FruitObserver < Observer

   def after_create(fruit)
     # Add to all the inventory lists
     InventoryList.find(:all).each do |i|
       i.stock.push fruit
     end    
   end
  end
You could use a mocha expectation to test this without using a single assert_blah like this:
  def test_when_creating_banana_observer_is_called
    banana = Fruit.new(:name => "banana")
    InventoryList.any_instance.expects(:push).with(banana)
    banana.save
  end

You don’t need to have assert_blah in all your tests – this is a perfectly acceptable test because it includes the expectation InventoryList.any_instance.expects(:push).with(banana).

Is your Mephisto Blog not accepting new comments?

Posted on April 18, 2008

This blog uses Mephisto – which is pretty cool and works a treat – but I realised to my horror the other day that the commenting system appeared to have stopped working.

It drove me bananas! Why would it work one day, but not the next! Why would it work on my local box but not on production?!?

Turns out there’s a known bug with Mephisto when used with Apache that prevents additional comments from being added to an article that already has a comment.

You can fix this by adding the following line to the bottom of your .htaccess file:

  DirectorySlash Off 

And voila – comments will start working again.

Thanks to Jason Gill for this tip.

Five tips for contributing to Rails

Posted on April 13, 2008
Note: these tips assume a basic understanding of how to contribute to Rails. If you’ve never contributed before I heartily recommend you check out Josh Sussers presentation Laying tracks or Ryan Bates excellent railscast on the topic.

Tip One – Test ActiveRecord tests with different database types

When creating a patch for ActiveRecord you need to make sure your patch works with different databases. I learned this the hard way when I submitted a patch that worked perfectly in mysql and broke in every other database type.

If you have the database management system set up correctly and also added the required databases (activerecord_unittest and activerecord_unittest2) then you can run the following rake task in the rails/activerecord folder:
  $ rake test_[database type]
Where [database type] is the database system you’re looking to run the tests on. For example:
  $ rake test_mysql
  $ rake test_sqlite
  $ rake test_postgresql
You can also use this rake task to run a specific ActiveRecord test. For example, to run the base_test.rb tests using mysql:
  $ rake test_mysql TEST=test/cases/base_test.rb

Tip Two – Run ActionPack tests in TextMate

When I’m working on a Rails application I get pretty addicted to running tests in TextMate with Command-R. I found when working on Rails patches that it wasn’t quite so tidy.

ActionPack tests typically have require ‘abstract_unit’ at the beginning of the file.

At the top of the test file add:
$: << ".." 

An explanation of what these strange hieroglyphs mean:

  • $: is the search path (you can think of it as being an array of directory path names)
  • ”..” the parent folder – you could have ’../tests/blahblah’ etc if you wanted to
  • << pushes an element onto an array

And now it finds ‘abstract_unit’ in the parent folder, allowing the tests to run within TextMate – hooray!

Obviously, if abstract_unit isn’t in the parent folder, then you should adjust this to search in the right folder for abstract_unit. For example:

$: << "../tests/helpers" 
Note: Make sure you remove the extra line before creating your patch

Tip Three – ActiveRecord script/console

Anyone who’s spent anytime working on an ActiveRecord Rails patch will realise that the included test models can get pretty complicated. That’s why I like to create a special IRB console for playing around with the relationships.

  • Still in the activerecord folder run:
    $ script/console
  • This opens a special IRB console that includes all the Rails test models and fixtures – allowing for cool stuff like this:

  • You can open it with different database types like this:
    $ script/console sqlite3
    $ script/console postgresql
    etc

Tip Four – Go through old unloved patches and fix them up

Stuck for ideas on how you can contribute to Rails? One great way is by going through old Rails patches in Trac and bring them up to speed.

Some patches work fine, but haven’t been accepted for a number of reasons:
  • They need documentation
  • They need tests
  • The code that the patch applies to has been changed

This link provides a list of patches that are untested, undocumented and incomplete.

Or you could just browse through the old open bugs here for patches that work but need some attention.

Tip Five – Validate other peoples patches

Last year, the Rails Core team made a decision that patches need to be verified by three other contributors before being considered for acceptance. With this arrangement, the Core team now no longer have to waste their time examining half-finished patches, and the quality of patches are higher.

Verifying a patch is more than just agreeing with the idea, it requires a bit of effort.

Here’s the steps you need to take to verify a patch:
  • Find a patch that needs verifying.

This bit’s easy. Just waltz on into #rails-contrib on freenode and ask “anyone want me to +1 their patch?” and prepare to be bombarded with requests.

  • Agree with what the patch does

This may seem obvious, but there’s no need to verify a patch if you don’t believe that the patch belongs in Rails.

  • Look at the source code

Give the code an eyeball in trac before downloading it. Make sure that the patch includes appropriate tests and documentation, and the code doesn’t have any glaring peculiarities. If it’s lacking in one of these areas post a comment on the ticket so that the contributor can make the necessary fixes.

If however you’re happy with how the patch looks then it’s time to take it for a test drive.

  • Update your own Rails repository

This is so that when you install the patch you can be sure that it patches cleanly. If it doesn’t then post a comment on the trac ticket letting the contributor know so they can fix it.

If you’re using subversion then run
    svn update
  • Download the patch

Sometimes trac tickets have multiple patch files, so make sure you’ve got the right one(s).

  • Install the patch

Now install the patch on your own repository using a command like:

    $ patch -p0 -i [patch_file.diff]
(Replace [patch_file.diff] with the file path of the patch you want to apply.) If the patch doesn’t apply cleanly you’ll get a message like:

    Hunk #2 FAILED at 738.
This is a sign that the code base has changed since the patch was created. The contributor will need to update the patch. Make sure you post a comment on the ticket with the details.
  • Run the tests to make sure they all pass
    $ rake test
  • Try out the patch with a test Rails application.

I like to keep my Rails repository in the vendor folder of a dummy application that for testing patches.

  • Verify

If the patch works, and there are no obvious side effects, then you can +1 the trac ticket. Simply post a comment on the ticket with something along the lines of:


    +1 tests pass

If you find that you’re the third person to verify a patch, then add the verified keyword. This signals to the core team that this patch is ready for examination.

  • Revert the patch
Run something like
    svn revert . -R

To ensure that the patch is no longer applied to your repository.

Wee issue trying to install git using MacPorts

Posted on April 11, 2008

The other day I wanted to install the hot new SCM git – and an easy way to do this is using MacPorts.

So I opened up the terminal and banged out:

sudo port install git-core
It chugged away installing nicely until it tried to install rsync as a dependency:

<snip>
--->  Attempting to fetch rsync-2.6.9.tar.gz from http://svn.macports.org/repository/macports/downloads/rsync
Error: Target org.macports.fetch returned: fetch failed
Error: Status 1 encountered during processing.
I fixed this by running the selfupdate command for MacPorts

sudo port selfupdate

After that the git installation worked fine.

Where's my blasted gems?

Posted on March 21, 2008
If you’re anything like me, and you keep forgetting whereabouts your gems are installed, use the following command:

gem environment
This will pop up a handy list like this:

RubyGems Environment:
  - VERSION: 0.9.4 (0.9.4)
  - INSTALLATION DIRECTORY: /usr/local/lib/ruby/gems/1.8
  - GEM PATH:
     - /usr/local/lib/ruby/gems/1.8
  - REMOTE SOURCES:
     - http://gems.rubyforge.org

Your gems are nicely tucked away within your GEM PATH directory