Future Ruby!
Courtenay : June 24th, 2009
The very nice folks at Unspace sent me a beautiful care package today - a “handwritten” note and a huge poster. It mentioned that Future Ruby is in mid-july in Toronto, and invited me to come with my team.
I’m such a sucker for this type of marketing, so take heed ye marketers. Send me posters and tshirts!
I wish I could make it - Ruby Fringe had great press - but my visa ran out, and I can’t leave the US until it’s sorted out. I’ll be encouraging my team to go - but it’s a fair trek from the west coast
The best thing about this is the Russian glyphs they using in the title. One of the guys in the office HATES it when people abuse the backwards “R”. I will hang this poster and mock him mercilessly with its presence.
Rails 2.2 gotcha - inline subclasses
Courtenay : May 15th, 2009
Due to the way Rails' development mode works, you need to make sure you don't define subclasses in your "concern" files like this:
# status.rb
class Status
include "status/filtering"
end
and then
# status/filtering.rb
class Status
module CustomAssociationExtension
end
end
Instead, you should have a file app/models/status/custom_association_extension.rb so that rails can easily find it.
Ticket: #1339 (note: not solved)
Rails 2.3.2: not ready for prime time
Courtenay : May 9th, 2009
I’d strongly advise against upgrading your application to Rails 2.3.2. I’ve hit quite a few bugs that have taken a big chunk out of several of my days, including:
- “can’t dup nilclass”, as reported here: http://groups.google.com/group/rubyonrails-core/msg/787b561d166abf53
- A strange bug in associations and rspec, http://groups.google.com/group/rspec/browse_thread/thread/7901db1b123eb93c
- Lots of upgrade issues with rspec requiring a rewrite of routing specs and erroneous missing templates (reported in their README)
- Anything that isn’t fixtures, but creates records in tests, will fail due to the Rails new way of doing nested transactions
Stick to 2.2 for a while longer – it’s not worth your time.
Rails 2.3 upgrade gotcha: aggregate methods are now OrderedHash
Courtenay : May 8th, 2009
In our open source ticket tracker xtt, we have code that looks like this:
has_many :memberships do
def contexts
proxy_owner.memberships.sort.group_by &:context
end
end
Basically, it lets people group their memberships to various projects by a context. So each user can have their own grouping for projects. If you don't have a context for a project, it shows that last, in an implicit 'etc' context. In the tests, we check for this behavior like
it "leaves nil context for last" do
@contexts = @user.memberships.contexts
@contexts.last.should == [nil, [memberships(:default)]]
end
However, since rails now returns aggregated association results (such as group_by or total with :group) as an ActiveSupport::OrderedHash, you don't get all those tasty array methods that Rails is so famous for (#last, #second etc).
ActiveSupport::OrderedHash is just some code that duplicates Ruby 1.9's hash functionality.
The easy solution here is to make your results into an array at some point, rewrite your tests, or send a patch to the rails team to mix in the Array monkeypatched code into OrderedHash.
it "leaves nil context for last" do
@contexts = @user.memberships.contexts
@contexts.to_a.last.should == [nil, [memberships(:default)]]
end
Caboose Doc Fund - still kicking ass
Courtenay : April 30th, 2009
Remember all those years ago when we raised a bunch of cash for Rails documentation? Still paying out, regularly. Pratik’s docrails project is chugging along with almost reckless abandon. Boy do these guides look great!
Here are the most recent three articles, and wow, are they high quality!
Sven Fuchs wrote this definitive guide to Rails Internationalization which is for “translating your application to a single custom language other than English or for providing multi-language support in your application.”
Cássio Marques wrote the excellent ActiveRecord validations and callbacks guide, which provides an in-depth look at validations, callbacks, the whole AR lifecycle, and then tells you how to write your own. This is a ground-up guide that takes you from noob to expert.
Finally, Ryan Bigg nailed the ActiveRecord query interface to the freakin’ wall. This is the be-all and end-all of ActiveRecord guides, folks.
A job well done by all, and they’re all richer for the experience, both knowledge and hard cash. Writing guides is how I got started in rails, and I’d strongly recommend any smart cookies out there write a guide to a part of the code on which they’re not so hot. As a side note, none of these people are from the US, which is a reminder to those of us North American-centric coders that there is a huge world of smart people out there.
Over 300 registered for cabooseconf
Courtenay : April 29th, 2009
Hey everyone! Railsconf is just days away, and O’Reilly tell us that we have over 300 people, and about 50 of you are NOT going to the main conference – Cabooseconf only! Shit yeah!
unconference
So, here’s what’s going to happen. We’ll run this in unconference style, which means, a big board with your sessions (if you want to run them) and hackfests. If you have any experience “running” an unconference, please hit me up, I’m a few organizational hands short this year.
hackfests
If you have an open source project, our room is ripe for the using. In fact, this was my original request of O’Reilly: that we are the official (as much as this exists) place for OSS hacking. Tables will be set up in circular fashion, and I’m bringing a supply of extension cables, squids and other such power devices. However, you should bring your own too, just to be sure. Sidebar, I’d LOVE to work on altered beast at some point.
Food
Last year, we had our friends sponsor the conf, which meant free food, energy drinks, and such. Due to the fucked way that Vegas operates with unions and profit-starved hotels (hah!) we can’t provide these, and I really don’t want to funnel any more money into the corporate machine. So, unfortunately, no free food at cabooseconf.
Rock band
This was a great hit last year. We WILL be bringing the xbox and some other toys which we’ll use on the projector.
Electronic musicians
Much like our pal Zed Shaw, this year I’ve been doing a lot of music (ma46 and telesonic commander). Completely unrelated to ruby or rails. So, if you have some cool gear (monome, synths, anything) bring a piece or two and we’ll have some nightly jam sessions. I’ll probably bring my Moog, a mixer, and kaoss pad. We should be able to send out midi sync over the network and a midi backplane, and I’ll bring a nice big loud speaker to annoy the hotel with.
Vegas Scam
admin : April 1st, 2009
Today we were trying to sort out running CabooseConf during Rails Conf in Vegas. As you may recall, last year we provided free lunch and beverages for you all to drink while you hack. This year, we're doing the same thing under the auspices of O'Reilly.
My favorite energy drink of choice right now is Function Alternative Energy. In fact, I love it so much that we go through a few cases every month. It has caffeine, Yerba Mate and guarana in a great mix that doesn't give you a crazy buzz -- just laser-like focus. This is probably a topic for another day, but the important point is that we got a sponsorship from Function (free drinks!) so that we could bring a couple hundred of these and hand them out to our programmer friends and get them hooked.
Now, as it turns out, you can't just do that. Not in Vegas. You have to pay everyone in line.
It costs me $1 per drink consumed, as corkage. Then, I have to pay the Chef's union another $0.60. Per drink. As the guy at the Hilton said, at least it's better than us providing you with water. That costs $3.75 per bottle.
Now, it's not about the money. I know that there are people ready to either sponsor our little anticonf or I can throw some of my own cash at it. That's totally not the point. I have a moral objection to giving these assholes any money at all.
Oh, and a bowl of pretzels? $30. For that, I hope they let you keep the fucking bowl.
How many of you are planning to come to Railsconf and just hang out at the free caboose conf?
CabooseConf '09
Courtenay : March 12th, 2009
Hey everyone! CabooseConf 09 is on again. For those of you who don’t know, we have been running a free anti-conference at the same time as the O’Reilly Railsconf behemoth. Last year, Chad and Gina approached me after the conference and asked if we would run it again this year, but under the banner of Railsconf itself. Keep your friends close, I guess ;)
I’m a big fan of going to conferences and attending the “hallway track”. So, this year it’s officially sanctioned.. Come to Vegas, network, hack, code, and don’t pay a cent. We have conference rooms staked out at the Railsconf hotel, and we’re doing our best to organize similar perks to last year (free energy drinks, etc.)
You do have to sign up at the O’Reilly “railsconf”:http://en.oreilly.com/rails2009/ site and get a badge. Did I mention it’s free? One thing you need to do – as usual – go write some open source code! No, you can’t use something you did two months ago. No, you can’t use some code on some PHP project. This is railsconf, so go show it like you mean it, and contribute something to rails. We won’t let you in unless you do. Seriously. (*Merb also accepted)
We hope to be hosting all the hackfests.. so bring your open source ruby codes.
The ultimate ruby training
Courtenay : March 9th, 2009
Over at @entp we teamed up with David Black, old school rubyist, trainer and mentor to collaborate on a training session. If you’ve been sniffing around Ruby or Rails and want to get a solid foundation, this is the session for you. If you work with people you’d like to truly understand idiomatic ruby, or just want to convert them to the one true way, this is where you should point your boss: http://entp.com/training/ The sessions will also be taught by Jeremy McAnally, who needs no introduction around here, and Rick Olson will be on hand to help take things to the next level.
They’ll be starting from the ground up, building the basics and producing a fine ruby coder out of you or your coworker (whoever happens to attend).
We’re holding it in Atlanta on the 1st of April, since that’s a pretty easy place for all you east-coasters to get to. The early bird pricing ends tomorrow, so now’s a good time to think seriously about signing up.
Open sourcing our twime tracker
Courtenay : January 16th, 2009
Oh my god, I just came up with a new phrase. Twime tracker. Shoot me now, please.
Anyway, about a year ago we started writing a “twitter meets time tracking” application, XTT, over at ENTP to track our time. It was more than that, really.. more like 37signals’ In/Out (which they hadn’t released yet), but also like a closed-group twitter-style status update, the difference being we track the times for each status.

It’s invaluable to see who’s working on what, but also, what people spend their time on.
We used XTT pretty much since day 1, and it works swimmingly for a team of 4-14 people (which is how much we’ve grown over the year). We let a limited number of beta testers use it, but it never really took off. I think this is probably because the users were typically single programmers who didn’t need to know what other people were working on.

Add to the fact that there are many other excellent time trackers out there (Harvest, for example) and I didn’t feel that I could turn XTT into a saleable product (it would require another few months of polishing, for not much of a return), so we let it languish. It works well enough for us, but other people just didn’t get it.
Finally, I decided to just open source XTT, and there it is on github: xtt. If you run a small team and want to check it out, let me know how it goes.
A few notes you might find interesting:
- Much of XTT’s timezone code was extracted and is now in Rails core itself.
- We take the user’s browser cookie timezone offset, and use that to automatically figure out their local time. We have people in timezones from the UK all the way across the US (3 different zones) and beyond, and it’s worked fine.

- It has a polymorphic notifier model called a Tendril that lets you notify Campfire or IRC (or anywhere!) when people change statuses
- It has a mostly-functioning AIM bot, with a patched version of the AIM library Net::TOC (I released this separately). By mostly-functioning i mean that. It has difficulty staying up :(
- The notifiers know that if you were on a project and then go work on something else, to notify (e.g. campfire) that you’re no longer working on that thing, just so your co-workers know.
- Each user gets their own “contexts”, which are a way of grouping projects. So, your contractors might group your projects under your company name, but the boss might group projects by client.
- Full import, export, and in-browser CSV editing of times.
- You can enter times in the past like this: [-25] for 25 minutes ago, or [-4h] for 4 hours ago, when you forgot to enter your time.
Be aware that this code is released under AGPL, which means that there are limitations on how you can use the code. The main one is you can’t run a hosted version of this unless you release the source code. Other than that, it’s a fairly liberal license.
Where to from here?
If you’re interested in helping out, go fork it and send a pull request. Here are some places that need improvement.
- There’s no setup/bootstrap
- There’s no UI on tendrils; right now it’s hard-coded and you have to add a Campfire row in console
- There are no blank-state messages (“You just signed up, here’s where to go from here”)
- Some of the time logic is just nasty (particulary chart*.html)
- There’s no limit if you accidentally forget to set “out”, on the maximum status time. So you could have a 10 hour time.. this could be limited with a user preference.
- The AIM bot goes down ALL the time. Rather, it just stops responding. I was thinking of adding something like, touching a file every time it loops; if the file gets older than 5 minutes, restart!
- While the AIM bot keeps a log of everyone’s “away” states (so you could, in theory, set someone “out” when they go offline) it’s not hooked up to anything. This could be a user preference, too.
- The AIM bot doesn’t rate-limit when it re-connects, so often it’ll just keep sending requests until it’s banned
- There’s a half-finished Jabber bot in there somewhere
- Things break when you add statuses that are in the past, but where there was a more recent status
- Some of the code is lightly tested
- I’d love to integrate with other services, such as recording times on lighthouse tickets based on user input (Attach blah to #125)
- Billable vs non-billable hours.
- Entering actual billing rates for projects/clients/contexts/people so you can actually create an invoice
- Create invoices
I look forward to how you might use this in your own company. Let me know!
If you want to file bugs, or want support, see our xTT Tender support site
Allowing custom CSS in your app
Courtenay : December 31st, 2008
There are a number of good reasons why you don't want your users providing their own CSS (for example, when theming their site). These are: taste (see: myspace) and security.
The former is pretty much your users' problem. The pages don't have to look terrible -- and in fact Myspace charges a LOT of money to do those custom movie or band pages (it's part of the service when you buy their primo ad space).
The latter, well, as it turns out there are a bunch of security vulnerabilities exposed in CSS. While these are mainly in IE, related to expressions (you can run javascript from your CSS). This means that users can steal others' sessions. So, while there are some excellent perl libraries out there for this, there hasn't been one for ruby -- until now! (at least that I could find).
So, here's my first attempt.
css_file_sanitize (github)
I stole most of the tests from LiveJournal's css sanitizing library, and rewrote the implementation in Ruby. I'd love to hear your collective feedback. It's a really lazy plugin; in fact, while it does have tests, you're best to just include the module in your model. This is a case of "it works on my machine" so send your patches!

Why aren't you testing?
Courtenay : December 15th, 2008
Those of you passionate about test frameworks or writing your own testing libraries can skip this article.
The rest of you, who don’t test: you’ve heard about it, you’ve seen us ranting about it, but, if you have a web application written in Rails and you don’t write tests for it, how do you know it works? (I’m guessing: refreshing it in your browser). How do you know it works for other people, too? If the company for which you work doesn’t have a testing culture, why don’t you step up and insist? Take a weekend and learn about it. Do the peepcodes, then evangelize at your company.
I’m stunned at how many Rails development companies out there just don’t test. At all. And worse, how many people apply for Rails jobs without any tests for the code they included as part of their application. If an employer gets two resumes, one where the coder has submitted a few files of code with tests, and the other which is just rails scaffold in test/, who do you think they’ll hire?
A plam for splam
Courtenay : November 24th, 2008
A few weeks ago I wrote a fun plugin to fight spammers everywhere; I call him, Splam. I thought I wrote this up somewhere, but I can’t seem to find the article. So, I must have dreamed it. I soft-launched it on Github, so those of you following my github profile will have seen some commits.
Splam is a “Simple, pluggable, easily customizable score-based spam filter plugin for Ruby-based applications”. I couldn’t find any other Ruby projects outside of Defensio and Akismet, both hosted services, so while you might say, “but those work perfectly well!”, you can run this locally and get instant feedback. Install it as a plugin, and include it into your ActiveRecord (or other PORO) like so:
class Comment < ActiveRecord::Base
include Splam
splammable :body
end
Easy, right? Splam works by looking at the field, and applying a set of rules. Some of these rules are pretty simple; most forum/comment spam is pretty simple, too. For example, it looks for words like "porn" or "erotic" or "viagra", and gives 10 points for each of these. Then it looks in links in the body, and gives another 20 points each time a word appears in the link text. (Actually, I modified the code so it gives 10^ rather than 10*. That means that each time you use a banned word, it's exponentially more likely it's spam).
Some of the other rules target the idiots who try to spam your Ruby forum with bbcode: [url= or [b] Then it gives you points for each chinese character, and more points for Russian glyphs. It looks for bad HTML (a href=http://...) as well as extra long lines, sentences with lots of words and no punctuation, too many words with lots of letters, and so on.
Splam gives you a spam? boolean, a splammable_score score, and the splam_reasons why it marked something as spam, along with the points for each infraction.
I originally wrote Splam for the new app, Tender Support we've been building at entp -- I've been tweaking it until it gets zero false positives against Defensio, Akismet AND our sturdy human spam checker, Will the Defender, against the complete set of support/help requests in the Lighthouse project. Interestingly enough, I had to add a set of "good words" which takes spam points away (things related to our business).
In this way, you can see splam as this horrible manual system with no training ability outside the code. It's an arms race, but I think we're not up against a particularly clever enemy[1]. I'd really like to add some clever bayesian magic to it, but since it works well enough for me right now, I'm gonna throw it down to you guys. I'd also like to make the points themselves a percentage rating (adding % chance that it's spam) rather than an absolute (>100 points, and it’s spam).
Splam has a test suite, so you can check it out, put some of your corpus in individual text files in test/fixtures/comment, and send me a diff or pull request with anything that gets incorrectly marked as spam or ham.
Splam is at http://github.com/courtenay/splam/tree/master.
[1] This isn’t really meant to be a challenge to spammers; interestingly enough, most of the spam we get is just mass-blasted crap that isn’t really targeted at all. We were talking in the company campfire about how you could really make a bunch of money out of “spam”; if you’re intent on selling shady drugs, peddling nootropics to programmers would work better than sex enhancers, HGH to competitive cyclists, and so on. You could probably build some clever markov chains to interact on forums, leading people back to your own site where you start the pitch.
new plugin: acts_as_git
Courtenay : November 14th, 2008
With the help of Jamie van Dyke at Parfait and Scott Chacon at GitHub, I'm pleased to announce Acts As Git (no, I don't like the name either). It's a simple plugin which stores all changes you make to a text field in a git repository. This is ideal for something like a git-backed wiki.
Look at it here: github or check it out from
git://github.com/courtenay/acts_like_git.git
From the README:
ALG automagically saves the history of a given text or string field. It sits over the top of an ActiveRecord model; after a value is committed to the database, the plugin writes the new value to a text file and commits it to a git repository. This way you get all the advantages of using Git as version-control.
Usage:
class Post < ActiveRecord::Base
versioning(:title) do |version|
version.repository = '/home/git/repositories/postal.git'
version.message = lambda { |post| "Committed by #{post.author.name}" }
end
end
To view the complete list of changes:
>> @post = Post.find 15
<Post:15>
>> @post.title
=> 'Freddy'
>> @post.history(:title)
=> ['Joe', 'Frank', 'Freddy]
>> @post.log
=> ['bfec2f69e270d2d02de4e8c7a4eb2bd0f132bdbb', '643deb45c12982dde75ba71657792a2dbdda83e6',
'1ce6c7368219db7698f4acc3417e656510b4138d']
>> @post.revert_to '1ce6c7368219db7698f4acc3417e656510b4138d'
>> @post.title
=> 'Joe'
It uses the excellent Grit library, and doesn't actually have a checked-out repository. The latest version of your data is still stored in the database. You can actually clone this repo and view the changes; pushing back to it won't do anything useful.
Plugin configuration style?
Courtenay : November 10th, 2008
I’m putting the final touches on a super-sweet versioning plugin, and I’ve discovered that we’re using several different metaphors for configuring the plugin options. I’d like to get some opinions/feedback on your preferred style.
The DSL
Using a DSL and passing blocks in which get instance evalled. I’m normally very scathing of DSLs; I think that they’re Yet Another Language for people to learn to use – it’s usually your very own write-only syntax – but it’s been super-fun implementing the backend to this.
class Monkey < ActiveRecord::Base
versioning do
author do
name { user.current.name }
message { "Commited via #{name}" }
end
repository "Joe's DataStore"
end
Hashes
This seems to be the Rails plugin default:
class Monkey < ActiveRecord::Base
versioning :author => { :name => lambda{ |u| user.current.name } }, :repository => "Joe's DataStore"
end
Class vars / methods
Easy to monkeypatch later
class Monkey < ActiveRecord::Base
will_version
@@version_repository = "Joe's DataStory"
def version_author
current_name
end
end
Are there others? Which do you prefer? Currently I’m using all three in this one plugin, and it’s very un-awesome.