I recently updated my RubyGems to 0.9.2. In that upgrade, require_gem
was deprecated in favor of gem
and running Rails would generate a bunch of deprecation warnings. However, it was easy enough to fix by running rake rails:update
in the app root.
Doing the update caused us some problems, though, because we are using the cached_model gem to store objects in memcached. cached_model was required in environment.rb before the Rails::Initializer.run
block but with the new autoloading mechanism, it didn’t work anymore because the Rails classes weren’t at the disposal of cached_model before the initializer block. Instead I got all these weird errors:
$ script/console
Loading development environment.
/opt/local/lib/ruby/gems/1.8/gems/cached_model-1.3.1/lib/cached_model.rb:21:NameError: uninitialized constant ActiveRecord
/opt/local/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/assertions/selector_assertions.rb:525:NoMethodError: undefined method `camelize' for "top":String
./script/../config/../config/../app/controllers/application.rb:1:NameError: uninitialized constant ActionController::Base
Lo and behold, the cached_model docs instruct to put the require line after the initializer block. This is the right way and should be ok in most cases. However, in our app, we also have an observer for the User
class, which is a subclass of CachedModel
. Observers are loaded inside the initializer block (config.active_record.observers = :user_observer
) and when loaded, they also initialize the actual ActiveRecord model they’re observing (in this case User
). But since User
subclasses CachedModel
, which is not loaded yet, we have a chicken and egg problem:
$ rake test:units
rake aborted!
uninitialized constant CachedModel
We can’t require cached_model before the initializer because ActiveRecord::Base
doesn’t exist then, and we can’t require it after the initializer because it would need to be initialized when the observers are loaded. What’s a man to do?
Rick Olson pointed me to a list of articles (1, 2, 3) that he recently wrote about the Rails initializing mechanism (+ a link to another useful article by Tim Lucas). This lead to a trick that solved my problem. Namely, writing a plugin.
The gist of the trick is that the loading of observers is deferred until all plugins are loaded. So I created an empty plugin called cached_model_plugin
, put the require 'cached_model'
line in its init.rb, and everything started working again. Woo-hoo!
The weird thing about this is that actually, the code in environment.rb after the Rails::Initializer.run
block should also be run before the observers are loaded. However, for whatever reason that didn’t happen in our case, so I’m happy that using a dummy plugin helped.
With the new config/initializers in Rails Edge this hack should become history, but until we update beyond 1.2.X, we’ll be camping happily with my plugin.