"Object is not missing constant XXX" and "A copy of YYY has been removed from the module tree but is still active" when using Rails metal

If you have a Rails metals that has enough code to have its own subdirectories that live in your Rails load_paths you can get stuck in dependency hell. The combinations of autoloading, rails reloading on development, and running through the metal can intersect in nasty ways: on the first request you get "Object is not missing constant XXX" and subsequent requests kick off "A copy of YYY has been removed from the module tree but is still active."

The easiest solution is to kill magic reloading for this metal's code by adding the metal's directories of code to the Rails load_once_paths and then using explicit require_dependency calls for any files that give you trouble. For example, I have a MadMetal that referenced a Mad which has a whole sub-directory structure of code that, for now, lives under lib/mad:

#config/environment.rb
config.load_once_paths += Dir["#{RAILS_ROOT}/lib/mad/**/"]

#app/metal/mad_metal.rb
require_dependency 'mad'
class MadMetal
  def self.call(env)
    if (env["PATH_INFO"] == '/the_path_to_my_metal')
      Mad.call(env)
    else
      [404, {"Content-Type" => "text/html"}, ["Not Found"]]
    end
  end
end

And wallah, no more conflicts between development auto-reloading and metal.

Of course, now you need to restart the server if you change code in lib/mad. In this case it's not a problem for me because the app is also a stand-alone rack app that I run with shotgun when I want development environment reloading.

Filed under  //   metal   ruby   rubyonrails  

Comments (0)

Leave a comment...