Rails 2.2 misbehaves when full app stack is not wanted

Today I wanted to make a minimal environment for running rake tasks, background jobs, scripts with script/runner and so on.

I started with this “config/environments/rake.rb” file:

config.frameworks = [ :active_record ]

config.cache_classes = true

config.gems.shift # removes Haml, the first gem dependency in environment.rb

config.plugins = [ :masochism, :will_paginate, :validates_existence ]

As you can see, I’m loading only ActiveRecord and gems/plugins that go with it.

But, I had a number of problems with this.

First, the environment-specific configuration files (“environments/ENV.rb”) are being loaded after the frameworks have been loaded. I don’t know why is this, except for the fact that require_frameworks method from Rails::Initializer uses silence_warnings from ActiveSupport. So, my config.frameworks override was useless.

Solution: I moved the require_frameworkscall to the start of Initializer#process. Of course, silence_warnings is not defined by that time so I defined a no-op method on Initializer with the same name.

Second, Initializer wants to load_application_classes – in other words, preload everything in the app/ directory (for thread-safety). This is a disaster, because ActionMailer and ActionController are not loaded.

Solution: add a special-case to prevent it, like

def load_application_classes

  super unless Rails.env.rake?

end

I probably could have just said config.cache_classes = false instead. Rails then assumes this is a development environment and doesn’t preload.

To conclude, this was all solved by subclassing Rails::Initializer, but I think Rails should support this out of the box. I propose the following:

  1. A tweak I described to solve my first problem;
  2. A configuration entry that specifies whether the environment should be in thread-safe mode. If not, don’t bother with preloading, connection pools in ActiveRecord and such.
    Thoughts?

Solution: I moved the `require_frameworks`call to the start of
`Initializer#process`. Of course, `silence_warnings` is not defined by that
time so I defined a no-op method on Initializer with the same name.

This seems like a reasonable change, there doesn't seem to be anything
important that it will be being moved in front of.

I probably could have just said `config.cache_classes = false` instead.
Rails then assumes this is a development environment and doesn't preload.

I'm happy with config.cache_classes = false as a work around if it
fixes the issue you had. It's a little dirty but shouldn't have any
performance impact as you're not calling reload!. Failing that, we
could add a config.preload_classes value to cover this case.

Koz (or others),
Has this issue has been addressed, and if so, in which commit?

-Chris

Hey Chris,

No, I don’t think it has, you’re welcome to do the change regarding “require_frameworks” (but you’ll have to drop silence warnings as I did). I was supposed to do it (because I ranted about it), but because I’ve patched the issue in my own app I forgot to do the same to rails.