Agile Web Dev Second Edition Arrives!

December 23, 2006

The postman brought a nice surprise from Amazon this morning, in the form of the second edition of Agile Web Development With Rails. I’ve had the book on preorder for a couple of weeks, but it’s been showing as a “won’t arrive until after Christmas” item right up until I last checked a couple of days ago.

First impressions of the book are good. It’s grown significantly since the first edition, with some notable additions to the sample application built in the second section. The book is a rewrite of the first edition rather than a cosmetic update which means that changes between the two aren’t signposted. It looks like it’ll take a bit of time leafing through to see exactly what’s changed.

You’ll also need to be running rails 1.2 to take full advantage of the shiny new stuff that’s covered. At the time of writing 1.2 isn’t yet available as a gem. There is a release candidate available though, and you can see what’s included and get installation instructions here.

It looks like I have some reading to do while I let my turkey go down this holiday season. Excellent.

Advertisements

URL Validation in Ruby/Rails

October 16, 2006

A project I’m working on has a need to validate URLs that users enter. Thinking that this would be just a straightforward exercise in regular expressions, I hit Google to find out who’d already done the hard work for me. The true spirit of reuse 🙂

A couple of false starts later and I’d found url_validation_improved. This seemed to be just the ticket, it has a regex for checking the URL format and even tests the connection.

To get started with my own validation I just wanted the regular expression part as my own project currently only needs to validate the format of the URL. Here’s the regex from url validation improved:

/^(http|https)://[a-z0-9]+([-.]{1}[a-z0-9]+)*

.[a-z]{2,5}(([0-9]{1,5})?/.*)?$/ix

Looking good. I’m not overly familiar with using regular expressions, so I plugged it into my model with validates_format_of and whipped up a unit test to throw a bunch of URLs at it. Everything was going fine, until I added the URL for a test server the application will be interfacing with to the unit test. As it’s a locally hosted rails app, the base URL is http://127.0.0.1:3000. Suddenly, my tests imploded. It turns out that this regex doesn’t allow IP speficied URLs or port numbers. Back to the drawing board Google I went.

Not finding anything much within Google, I started to wonder whether any of the built-in Ruby classes or libararies could help. It wasn’t long before URI caught my eye, flirting with me and giggling as it showed off its parse method, which takes a uri string and returns an appropriate URI subclass representing the URI. The hussy. Not only does it do that, but it raises a URI::InvalidURIError if the uri given is, well, invalid.

Ripping the disappointing validates_format_of from my model, in went a shiny new validate method. All it has to do is check wether a URI::InvalidURIError has been raised, and also ensure that the returned URI subclass is for a protocol that’s acceptable. Here’s the whole thing:

def validate
  begin
    uri = URI.parse(url)
    if uri.class != URI::HTTP
      errors.add(:url, 'Only HTTP protocol addresses can be used')
    end
    rescue URI::InvalidURIError
      errors.add(:url, 'The format of the url is not valid.')
    end
  end

As there was now a possibility of two different error messages appearing on my model I had to update my unit test. Once that was done, everything passes. The balance of the universe is restored.

There’s just a couple of caveats. Sometimes, URI.parse returns a URI::Generic, which is the parent of the other URI types. I’ve not looked deeply into why this is, but it seems to happen when URI is sure enough that the string you’ve passed really does represent a URI, but can’t actually identify a protocol. Since I know I only want to deal with valid HTTP addresses, I restrict my code to only accept those as valid.

It should also be noted that there are some subtle differences between URIs and URLs (URLs are a subset of URIs) but finding out what that means in practical terms seems to be tricky. I’m making the assumption that if a string passes this validation that I can use it as what I would think of as an URL.

Interestingly, the url_validation_improved code calls URI.parse about 5 lines after it checks URLs against the regex. I wonder why it don’t use that as the test of URL validity…?


Deleting elements inside each. Bad things ensue.

October 4, 2006

Last week a colleague was telling me about some difficulty he was having convincing someone that a web-browser based expandable tree view of data couldn’t be all that difficult. You know the sort of thing, very similar to a graphical file system explorer where you can expand branches and generally have a good sniff around your hierarchical data set.

It nagged at me the rest of the day. How hard could it be to do? I finally cracked and decided to whip up a quick Rails prototype. 2 hours later and I was done. With test data in my database I could use my browser just like Windows Explorer, expanding branches merrily as I went. All was good. Or so I thought.

On closer inspection, something was wrong. The code that was called when the user wanted to collapse a branch wasn’t working right, any expanded sub-branches remained open. I was holding a list of the expanded branches in the user’s session, and all the code had to do was remove the collapsing branch (and any of its expanded children) from the list.

Here’s the original code (the model is using acts_as_nested_set, which is why the logic to check whether a node is a child of the one being collapsed is coded the way it is):


session[:expanded].each do |party|
  if(collapsed.lft < party.lft && collapsed.rgt > party.rgt)
    session[:expanded].delete party
  end
end

Hmmm. It seems to be doing the right thing. Old Ruby hands (and those with more switched on brains than me when I wrote this) will already see what took me a long time to find out with breakpoints and irb. As I looked at the code execution at breakpoints I fell into an old, old trap. Using acts_as_nested_set was something new for me, whereas handling arrays was as old as the hills. I managed to convince myself that the problem was in the “if…” logic. There must be an error in it that’s failing to properly identify children of the node being collapsed. It took me a while to finally admit that, no, the logic was right and the error was elsewhere.

As soon as I did that, the answer hit me. I was deleting items from an array while I was iterating over it with each. This is the Ruby equivalent of crossing the streams. Every atom in your body won’t simultaneously explode, but something bad will definitely happen.

It didn’t take long to find an answer, thanks to my new friend delete_if. This handy method takes a block, and deletes all elements of an array for which the block returns true. The balance of the universe is restored, and I can feel happy at learning lots more about debugging Ruby with breakpoints and irb.

Remember, don’t cross the streams!