Space Vatican

Ramblings of a curious coder

Selenium and Firefox 3

I recently spent a bit of time making our Selenium tests play nicely with Firefox 3 and spent quite a lot of time starting at

1
Preparing Firefox profile...

Selenium would launch Firefox, and then Firefox would just sit there doing nothing. Eventually some digging around found a ticket on the Selenium issue tracker. It turns out Selenium installs a tiny little extension into the Firefox profiles it generates that basically just lets selenium kill firefox by telling it to go to a magic chrome url. Firefox extensions specify which versions they are compatible with and the one embedded in selenium had 2.0.0.* as their maximum version (and this is still the case with the latest downloadable release (although you could of course download the nightly builds)).

It seems that this was the only thing from keeping selenium and Firefox 3 playing nicely together as changing the maximum version to 3.0.* got all our tests passing again with our existing version of selenium (0.9.2).

All I had to do was extract the relevant files from selenium-server.jar:

1
2
3
4
5
6
7
8
9
10
jar xf selenium-server.jar \
customProfileDirCUSTFFCHROME/extensions/readystate@openqa.org/install.rdf
jar xf selenium-server.jar \
customProfileDirCUSTFFCHROME/extensions/{538F0036-F358-4f84-A764-89FB437166B4}/install.rdf
jar xf selenium-server.jar \
customProfileDirCUSTFFCHROME/extensions/\{503A0CD4-EDC8-489b-853B-19E0BAA8F0A4\}/install.rdf
jar xf selenium-server.jar \
customProfileDirCUSTFF/extensions/readystate\@openqa.org/install.rdf
jar xf selenium-server.jar \
customProfileDirCUSTFF/extensions/\{538F0036-F358-4f84-A764-89FB437166B4\}/install.rdf

This extracts the files (and the directory structure containing them). To be honest I’m not entirely sure of the difference between all of these extensions - safest bet seems to be changing them all. Now edit all of the .rdf files (they’re just text files) and change the maximum version from 2.0.0. to whatever you want (for example 3.0.) and put them back in the jar:

1
2
3
4
5
6
7
8
9
10
jar uf selenium-server.jar \
customProfileDirCUSTFFCHROME/extensions/readystate@openqa.org/install.rdf
jar uf selenium-server.jar \
customProfileDirCUSTFFCHROME/extensions/{538F0036-F358-4f84-A764-89FB437166B4}/install.rdf
jar uf selenium-server.jar \
customProfileDirCUSTFFCHROME/extensions/\{503A0CD4-EDC8-489b-853B-19E0BAA8F0A4\}/install.rdf
jar uf selenium-server.jar \
customProfileDirCUSTFF/extensions/readystate\@openqa.org/install.rdf
jar uf selenium-server.jar \
customProfileDirCUSTFF/extensions/\{538F0036-F358-4f84-A764-89FB437166B4\}/install.rdf

Voila! all done

Watch Out for Has_one :through and :include

I’ve seen enough people confused about this that it’s probably worth broadcasting this slightly more widely. In a nutshell, :include of has_one :through associations is broken in Rails 2.1. Rails 2.1.1 and higher are fixed.

As you may recall, :include takes ones of two different paths.

In the first (the default) Rails loads parent records first, and will then load all the child record of all those parent ones in one go. Unfortunately in Rails 2.1 this isn’t done quite right and the net effect is that the associations are loaded normally and then preloaded. This was fixed as of fdeeeaea and is included in Rails 2.1.1

In the second case Rails generates appropriate join statements. This is used when you have conditions or orders on the joined tables and also if you have a count or a sum which uses columns from the joins tables. This just plain wasn’t implemented, so it was being treated as a plain old has_one which results in an angry message from the database about you referencing a non existant column name. This was fixed as of bff0f5fb and like the previous fix is in Rails 2.1.1

RailsConf Presentation Code

The code from our presentation is now available here. It’s worth a look even if you weren’t at our presentation.

Knock yourselves out!

Thoughts on Jeremy’s Keynote

I really enjoyed Jeremy Kemper’s talk on wednesday. The sort of talk that has you itching to run home and try out what you’ve seen. All good stuff. For those of you who weren’t there, Jeremy was talking about performance.

The key point is that it’s all about the user experience: how fast do our users think the app is? Part of it is your ruby code (and Jeremy had plenty to say about that, with GC tips, profiling tips etc…) but a huge chunk is the network. A common trick is to bundle up your assets, what with the limit on the number of concurrent loads from a domain and the part that latency plays, loading 1 medium or biggish javascript (or stylesheet file or whatever) is almost always preferable to 5 small files. With 2.1 Rails makes this easy and will bundle up your js for you, but there’s another trick you can play.

You could stick assets like your javascript files on some sort of content distribution network, close to your users wherever they are. This would be an inordinate amount of effort to go to though just to host a few javascript files. Luckily, google has done that for you with their Ajax Libraries API. They are hostting copies of common javascript frameworks, including prototype, scriptaculous, dojo, jquery and mootools. You get to use their content distribution network and can assume they’ve got all the caching and compression stuff done right. The libraries are all versioned too (ie you say ‘give me prototype 1.6.0.1’), so no worries about that.

There is of course another advantage: instead of your browser caching a copy of prototype.js from every site that uses it, your users will only be caching it once (per version). Chances are when they come to your site it will already be in the cache.

Jeremy also mentioned the importance of putting yourself in your users shoes and seeing what your webapp is like when viewed through a slow or high(er) latency connection. I described one way of doing this alternative a few months ago and it really can be quite the eye-opener.

Ways in Which the Console Tricks You

IRB, and by extension Rails’ script/console is an incredibly useful tool. Being able to explore your objects or an API without having to write and compile a test program each time is absolutely priceless. There are however a few cases where the console can lead you astray.

When you evaluate something in the console it will display the result of calling inspect on whatever your statement(s) returned. Inspect is just a function so it can lie to you, be selective about what it shows or even have side effects.

Prior to Rails 2.0 the inspect function on ActiveRecord::Base dumped pretty much everything known about the object. This could get a bit cumbersome quite easily. For example if an association was loaded then the dump of all those objects would be included in the output taking up pages and pages and adding very little value. Starting with Rails 2.0 only the value of each attribute is listed:

1
2
>> Conversation.find :first
=> #<Conversation id: 2, title: nil, created_at: "2008-07-22 00:12:24">

Rails doesn’t list all attributes however: it knows which columns exist on that table and uses that information to destroy only those attributes. This often confuses people who are using :select to add attributes as it looks as though attributes aren’t there. Oh ye of little faith who do not believe until they have seen!

1
2
3
4
>> c = Conversation.find :first, :select => "*, 'hello world' as bonus_attribute"
=> #<Conversation id: 2, title: nil, created_at: "2008-07-22 00:12:24">
>> c.bonus_attribute
=> "hello world"

The extra piggy backed attribute was there all along, ActiveRecord’s implementation of inspect just chose not to show it to you. In theory an object’s implementation of inspect could do anything it wants. Usually it will be trying to be helpful, but that’s not to say it won’t mislead you.

Side effects

Every now and again the following pops up on one the the rails mailing lists or IRC channels:

1
2
>> conversation.messages
=> [#<Message id: 1, body: nil, conversation_id: 2, created_at: "2008-07-22 00:12:30"]

ZOMG! Just doing that loaded the association (or the all objects in the named scope), so doing conversation.messages.find… will load the collection before doing the find. What a waste! If only it were actually true.

Association proxies are slippery things. You may have already noticed that they claim to be arrays, look like arrays and yet clearly aren’t as they have a whole bunch of extra methods (which aren’t singleton methods). A full discussion of association proxies is something there’s no time for today, but the basic idea is that they implement specific methods like find (do a find that is scoped to the association) or count (does a SELECT COUNT(*) FROM …). If anything else happens (ie if method_missing is hit) then they load the association and propagate the called method to the target array.

When I typed in conversation.messages the relevant methods were called and an instance of an association proxy was returned. IRB then wanted to display it and so called inspect. Association proxies don’t implement that method and so the collection was loaded and inspect called on that. In order words conversation.messages doesn’t actually load the collection, it’s what IRB did with it afterwards that did. In a standalone script or program this wouldn’t happen at all. Pheww, Rails isn’t stupid.

There’s a little trick you can use in cases like this when want to stop irb inspecting something that will have a side effect such as the one described above or because the output from inspect would be very long:

1
x= (1..100000).to_a; false

Instead of printing several pages of the numbers from 1 to 100000 this just prints false. When irb evaluates that line the last statement is false (you could put anything you want there) and so the return value from that is what irb calls inspect on.

Fun with local variables

Try the following snippet:

1
2
eval("a=1")
puts a

If you paste it into IRB it works just fine, but if you paste it into a script and run that then it won’t work (you’ll get a undefined local variable or method ‘a’ ). Local variable scope is one of those things that are just a little bit fiddly in ruby. For example local variables created by eval are only visible from subsequent calls to eval. The big difference here is that ruby loads and parses your script in one go whereas irb does it line by line. The pickaxe has some more discussion on this.