Archive for January, 2007

Stupid mistakes and helpful hints

Wednesday, January 31st, 2007

I’m English. Which means I spell English and not Yank.

This also means that I waste hours of my precious time wondering why my constructor is not working when in fact I have written

 def initialise(params = nil)   super   do_whatever end

Spot the error?

When using Single Table Inheritance and overriding validate, don’t forget to call super in your descendant class, otherwise validate doesn’t get called in your super-class. Obvious but it has caught me out.

And lastly, if you are using attr_accessor to create “temporary” attributes and you want to use validations on them, you will find you get a "NoMethodError: undefined method `my_attribute_before_type_cast' for Whatever". However, the following method (adapted from Rails Recipes – recipe 64) will fix it:

 def method_missing(symbol, *params)   if (symbol.to_s =~ /^(.*)_before_type_cast$/)     send $1   else     super   end end

Basically, any method call ending in "_before_type_cast" will be re-sent without the suffix – so calling your temporary accessor itself.

Incidentally, I can’t get Recipe 64 to work with Rails 1.1.6 (not tried with Rails 1.2.1), which is why I came up with the Pseudo-Model trick.

It’s a shame …

Thursday, January 25th, 2007

It’s kind of sad that all Java’s promise was destroyed by bad management (and not Microsoft – although you could argue it was fear of Microsoft).

Safari, So Good, So What!

Tuesday, January 23rd, 2007

I rewrote my application to take advantage of the new Restful Urls in Rails (an article on this coming up). I also got rid of the messy session-managed login code and thought I would use a nice and easy HTTP authentication scheme (so my eventual API can use the same mechanism as the main application – plus it minimises that “nasty” server-side state).

All my tests passed. Nice.
I ran through the local application in Camino. Nice.
I capistranoed onto the server. Nice.
I ran through the deployed application in Safari (I wanted to grab some screenshots and I use Shapeshifter – I leave Safari unskinned just for this). Boo! Some of the links didn’t work.

I examined production.log. The filter chain has been halted – no yield. I examined the Rails source code. Why is the filter chain being halted? I looked through the HTTP Authentication source code. It looks like it is working correctly. Why are only some links not working? The authentication is obviously working for part of the application.

Then I noticed. It was the new-style Urls that were failing … http://myserver.com/thingies/34;edit – it’s the semi-colon! A few more tests proved it.

And then the killer. It works fine in IE (both 6 and 7). It works fine in Camino. It works fine in Firefox. It’s just Safari. Apple’s flagship browser doesn’t work with Apple-loving Rails. I then tested in OmniWeb … no joy there either. So WebKit doesn’t like Restful Rails.

A quick search later digs up this article - with a fix. Basically it overrides url_for and examines the User Agent – if it’s AppleWebKit then Url-escape the semicolons. My Urls look ugly but at least they work.

Default values in your models

Thursday, January 18th, 2007

*UPDATE* Do not put the default value code into your initialize method, it turns out that, under certain circumstances, it may not be called. Instead, move it to after_initialize.

This may be obvious but as it took me a little while to figure it out, I thought I’d share it with you.

If you want you have default values, the easiest way is to set your defaults within the table. But often, that is too late. In your new action, you want the defaults to appear within the form (or whatever). So instead, you have to set the defaults in the constructor – but in such a way that won’t interfere with Active Record’s standard behaviour.

In particular, there are several ways of instantiating an object:

  thingy = Thingy.new

This creates a brand new thingy, with blank values (for example, in a new action).

  thingy = Thingy.new params[:thingy]

This creates a brand new thingy, with values taken from the supplied parameters (for example, in a create action).

  thingy = Thingy.find params[:id]

This creates a brand new thingy, loaded with values taken from the database.

Internally, ActiveRecord::Base’s constructor takes a hash as a parameter – with a default value of nil. So if you want to override it, you have to honour its original semantics, otherwise the rest of the framework will complain.

So, imagine the Thingy model has attributes “name” and “price” that you want to initialise:

def initialise(params = nil)  super  self.name = "default"  self.price = 1.50end

This won’t work – because the second and third instantiations will have their values overridden. Instead, what you need to do is this:

def initialise(params = nil)  super  self.name = "default" unless self.name  self.price = 1.50 unless self.priceend

You could use

self.name ||= "default"

but I had one weird situation where it didn’t work (unexplained) and I also find it more readable.

If you find this useful then please take a look at some of my other writing – or recommend me on Working with Rails. Cheers.

ARTS and Rails 1.2

Thursday, January 18th, 2007

I recently ran into some problems when upgrading an application from Rails 1.1 to Rails 1.2. RJS tests (using ARTS) that previously worked fine suddenly started failing (cannot find X in response, when I could see X in the response, right in front of me).

I dived into the ARTS code and came to the following conclusion: the JavaScriptGenerator has changed in some way; in particular, each fragment of JavaScript was separated by a newline before and is not any more. The original ARTS code would split the response into an array of strings (split by newlines) and then use Array#include? to look for the fragment. I have changed it to look like this:

def assert_rjs(action, *args, &block) if respond_to?("assert_rjs_#{action}")   send("assert_rjs_#{action}", *args) else   assert @response.body.to_s.index(create_generator.send(action, *args, &block)), generic_error(action, args) endend

In other words, instead of splitting into lines and looking for an exact match, I simply examine the entire response body for the fragment. I have reported this to Kevin Clark (he says he has had no problems with edge rails, but maybe that has changed again since 1.2); however, if you are experiencing weirdness try editing the assert_rjs method in arts/lib/arts.rb as described above.

Semantix

Saturday, January 13th, 2007

An excellent introduction to using Semantic HTML – why and how.

Obligatory iPhone Post

Wednesday, January 10th, 2007

It runs OSX!!!!
I bet that’s what prompted the switch to Intel processors … cheap XScales (or whatever it uses).
The Zune looks pretty dated already.
I’m not getting one. At least for a couple of years.

Dealing with Disaster

Wednesday, January 3rd, 2007

Following on from 37Signals’ recent post about dealing with mistakes, Julian Bicknell, CTO of Developer Express Inc recently sent my company an email for a problem with their automated announcements system. It had been spewing out multiple repeat copies of an announcement and was then followed by an apology from Mr Bicknall. Fair enough. But what made it special was the ending …

I’m sending this as a general email because I wanted to apologize to everyone as quickly as possible. However, by my sending it, I’m not trying to avoid any personalized interaction with you: you can, if you want, complain to me directly rather than to a anonymous email alias. You can reach me at XXX@devexpress.com, or, if you’d rather, on my cell phone at +1 XXX XXX XXXX (I’m on Mountain Time in the US, GMT-7).

(I’m hiding his details as I’m a customer and you’re not). It was the mobile number that did it for me.

IIS, FastCGI and Rails

Wednesday, January 3rd, 2007

Brent Heinz contacted me last year asking me to point to his new installer. It’s taken me a while to get round to it but here it is … automating all the rubbish that I wrote about all those months ago.

Doodles and Business Cards

Tuesday, January 2nd, 2007

Excellent site and excellent article