I am proposing a patch to help cope with the dreaded Rails LoadError:
LoadError: Expected foo.rb to define Foo
In Ruby, it is simple to load code, just require
it. In script/console:
>> require 'account_controller'
=> ["AccountController"]
Rails extends this to magically find classes just based on their name:
>> AccountController
=> AccountController
Most of the time, if a class does not exist, you get a helpful exception:
>> AccountController
MissingSourceFile: no such file to load -- hpricot_scan
Ah, so my AccountController
depends on hpricot, which isn't available for some reason. Solution: go find hpricot.
But once in a while this problem presents a different symptom:
>> AccountController
LoadError: Expected account_controller.rb to define AccountController
This is confusing, since account_controller.rb does define AccountController
! Experienced Rails developers know that this cryptic message actually means "Something went wrong in application_controller.rb, but Rails swallowed the real exception." After being bitten by this on three different projects in the last two weeks, I decided to track the issue down. Turns out the problem is in how fixtures get loaded:
begin
require_dependency file_name
rescue LoadError
# Let's hope the developer has included it himself
end
After fixtures swallow the real MissingSourceFile
for a subdependency such as hpricot, ActiveSupport raises a misleading LoadError
for the original dependency (account_controller.rb) that references hpricot.
In a perfect world, I would simply have fixtures stop swallowing LoadErrors. But the comment strongly suggests that some code depends on this behavior. So weaker sauce is to at least log the problem:
def try_to_load_dependency(file_name)
require_dependency file_name
rescue LoadError => e
ActiveRecord::Base.logger.warn("Unable to load #{file_name}, underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
end
If anybody knows how to distinguish the confusing LoadErrors from the expected ones, please go and improve the patch.