Archive for January, 2008

Rails: When an Uninitialized Constant Hits the Vent

Tuesday, January 29th, 2008

Last two weeks I was seeing the production server of one of my clients hit the same error over and over with no visible pattern. This second it works, the next it fails and leaves the Mongrel cluster in an undefined state somewhere between this world and hell.

The error I’m referring to is:

NameError (uninitialized constant MyModule::Utils::NetSession)
  ... backtrace follows ...

I need to repeat that it comes and goes under some non-obvious circumstances, and is hard to recreate. Fortunately, I found the solution and here’s what it was.

I have a directory hierarchy like below. I’m sure when you see it, it all becomes obvious and simple, but it wasn’t for me at that time as there were many files that I omitted below.

/lib
  /my_module
    klass1.rb
    ...
    utils.rb
  /utils
    net_session.rb

The piece of code in klass1 that failed looks as follows:

def new_session
  Utils::NetSession.new
end

Simple, heh.

Utils.rb is a helper module which is included into MyModule, but apparently loaded only when really necessary (it’s the only explanation why it didn’t fail all the time, as you will see). When it is loaded and included, the MyModule::Utils becomes defined, and Utils::NetSession resolution starts to fail. It happens as Rails begins looking for Utils name space from MyModule, finds MyModule::Utils and doesn’t find any NetSession there. That’s pretty much all to it.

The solutions are:

  • Either rename utils.rb (which I did in favor of utilities.rb), or
  • Use “::Utils::NetSession.new” (which is not safe as one day you can forget about the leading “::”, and get back to roots)

Hope this helps someone like me fighting the way through these extremely infrequent but painful Rails gotchas.

RSpec: Hierarchical Specifications

Tuesday, January 1st, 2008

RSpec is full of great features, but some of them either not very well documented or hidden to a naked eye. No wonder if you never discovered hierarchical specifications.

Traditionally, we write specifications like this:

describe AClass, "when doing this" do
    ...
end

describe AClass, "when doing that" do
    ...
end

Now imagine that you have some very similar specs with some common initialization:

describe AClass do
    before do
        ...
    end

    describe "when doing this" do
        before do
            ...
        end
        ...
    end

    describe "when doing that" do
        before do
            ...
        end
        ...
    end
end

You can see that you have common initializations for examples from both specifications and specific initializations for examples from each.

In the previous post I wrote that I prefer not to define helper methods outside the specification definition as they become global and tend to intersect with methods defined in other specs. So, what is the solution?

Assuming that you have a method “authenticate” that you need to call before every example in several specifications, you can define an upper-level specification “authenticated” and group other specs, like this:

describe AClass, "(authenticated)" do
    before do
        authenticate
    end

    describe "when doing this" do ... end
    describe "when doing that" do ... end

    def authenticate
        ...
    end
end

Now you have it all in a safe way!