Thursday, January 08, 2009

Ruby tip to handle missing records

Here's quick and simple tip to cleanly handle non-existent records in Ruby.

By default if you try to use find(id) to fetch a record from your database and the id doesn't exist you'll get a RecordNotFound error like:


>> r = Record.find(9999)
ActiveRecord::RecordNotFound: Couldn't find Record with ID=9999
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:1383:in `find_one'
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:1366:in `find_from_ids'
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:541:in `find'
from (irb):3

You could wrap it with a begin and rescue and have the rescue clause create a new record such as:

begin
r = Record.find(id)
rescue
r = Record.new
end

Or you could simply use find_by_id which will return nil if the record is not found and re-write it as:

r = Record.find_by_id(id) || Record.new

Tuesday, December 23, 2008

Merb and Rails Merge

The competing Ruby frameworks, Rails and Merb, have decided to join forces!

Here is the announcement from Rails creator David Heinemeier Hansson and the similar announcement from the Merb perspective from Yehuda Katz.

Keep up with all the latest Ruby and Rails news at Ruby Rails Review.

Tuesday, December 16, 2008

Ruby on Rails News Site

I haven't been very active on this blog recently, but I've been keeping plenty active on other endeavors. One of which is the Ruby Rails Review which my friend, Brian Burridge, announced last week. As he mentioned in the announcement I created a very easy to use CMS tool which allows us to drag-and-drop the news stories all over the page for placement (or addition and removal), as well as a bookmarklet to simplify the process of adding new stories. I've very happy with how it turned out, unfortunately no one gets to see it but he and I.


Tuesday, September 09, 2008

Campfire activity notifier for Gnome, KDE, or console

The 37signals blog points out a simply Ruby script for KDE that will give you a visual notification when a new message is posted to a Campfire chat room. I have modified that script to work for Gnome as well as KDE, and additionally a text console. I also made a few other additions such as:

  • Allow you to specify a specific chat room(s) as a command line argument
  • Multiple chats rooms can be monitored concurrently using threading
  • Added the Campfire logo to the notifications
  • Added some initial status messages to display login status, room topic, and current people in the room
  • Display of the last 3 messages of the current day's transcript so you know what's going on without need to login
  • Filter out ads
Here is my version of the script:
#!/usr/bin/env ruby

# == Synopsis
#      Program to monitor a campfire chat room
#      Modified from code provided at: http://www.snailbyte.com/2007/09/13/campfire-activity-notifier-for-kde/
#
# == Usage
#      campfireMonitor [roomName] [roomName] ...
#
# == Author
#      Steven Pothoven and Snailbyte Ltd.

require 'rubygems'
require 'tinder'
require "cgi"

class App
  VERSION = '0.1.1'

  def initialize arguments, stdin
    # default settings
    campfireSubdomain = 'mySubdomain'
    campfireUsername = 'user@email.com'
    campfirePassword = 'password'
    roomNames = ['Room1', 'Room2']
    if arguments.length > 0
      roomNames = arguments
    end

    @ui = 'gnome'
    @campfireIconPath = '/path/to/campfire-logo.png'
    # define you favorite audio player and audio file here for audio notifications
    @soundCommand = 'mplayer /usr/share/sounds/pop.wav'
  

    @campfire = Tinder::Campfire.new campfireSubdomain
    if @campfire.login campfireUsername, campfirePassword
      alert nil, "CampfireMonitor", "Successfully logged in #{campfireUsername}"
      @rooms = roomNames.collect { |roomName| @campfire.find_room_by_name roomName }
      # remove any invalid rooms
      @rooms.delete(nil);
      @rooms.each do |room|
        notify room, "CampfireMonitor", "Entered room."
        notify room, "CampfireMonitor", "Topic is: #{room.topic}.".gsub("'","")
        notify room, "CampfireMonitor", "Current users are:  #{room.users}.".gsub("'","")
      end
    else
      alert nil, "CampfireMonitor", "Failed to log in #{campfireUsername}"
    end
  end

  # display notifcation message
  def notify room, user, msg
    if msg and msg.size > 0
      msg = CGI.unescapeHTML(msg);
      if @ui == 'kde'
        system "dcop knotify default notify eventname \'#{user}\' \'#{''+@campfire.uri.to_s+'/room/'+room.id+'/'+room.name+': ' unless room.nil?} #{msg}\' '' '' 16 2"
      elsif @ui == 'gnome'
        system "notify-send -i #{@campfireIconPath} '#{user}' '#{''+@campfire.uri.to_s+'/room/'+room.id+'/'+room.name+': ' unless room.nil?} #{msg}'"
      else
        puts "#{room.name+':' unless room.nil?}#{user} - #{msg}"
      end
    end
  end
  
  # notify with sound
  def alert room, user, msg
    notify room, user, msg
    if @soundCommand and @soundCommand.length > 0
      system @soundCommand
    end
  end

  def run
    # first get any missed messages for today
    threads = []
    @rooms.each do |room|
      thread = Thread.new do
        room.transcript(Date.today).last(3).each do |m|
          if !m.nil? and m[:message] and m[:message].size > 1
            notify room, m[:person], m[:message].gsub("'","")
          end
        end
      end
      threads << thread
    end
    threads.each { |thread| thread.join}

    # listen for more messages
    threads = []
    @rooms.each do |room|
      thread = Thread.new do
        notify room, "CampfireMonitor", "Waiting for messages..."
        room.listen do |m|
          if !m.nil? and m[:message].size > 1
            unless m[:person] == "Ad"
              alert room, m[:person], m[:message].gsub("'","")
            end
          end
        end
      end
      threads << thread
    end
    threads.each { |thread| thread.join}

  end
end

app = App.new(ARGV, STDIN)
app.run
I'm sure you can think of plenty more customizations such as command-line options for all the default settings, etc. But I wanted to keep it fairly simple. One last thing, here is the cropped version of the Campfire logo I use for my notifications (campfire-logo.png):

Tuesday, September 02, 2008

Google Chrome (Chromium) JavaScript speed

Today Google announced and released their own web browser named Chrome (aka Chromium). They even made a nice comic book to describe the advantages of it.

One of the key features they advertise is faster JavaScript execution due to the V8 JavaScript VM. So, I decided to test it using my JS-BogoMips test.

Here are the results of my tests (Windows Vista on Intel® Core™2 Quad Q6600):
Firefox 3:
JS-BogoMIPS (3x) = (0.436779 + 0.446775 + 0.450888) / 3 = 0.444814

Chrome:
JS-BogoMIPS (3x) = (2.758552 + 2.884791 + 2.881541) / 3 = 2.841628

which is a 6.4x speed increase!