Mathias Meyer
Mathias Meyer


In an earlier post I wrote about namespacing your Rails model. There’s an additional issue that must be thought of when doing so. Rails (of course) has conventions dealing with namespaces.

Normally, when you put classes in namespaces, like Admin::User, Rails normally expects this class to be in a folder admin in your app/models directory. Responsible for this is the method load_missing_constant in the module Dependencies, part of ActiveSupport. It also uses the namespace to build the table name. So Admin::User would result in admin_users. This isn’t always a desirable outcome. Of course you could set a table name explicitly:

class Admin::User < ActiveRecord::Base
  set_table_name "users"

If you need to avoid namespace clashes, that’s an acceptable option. But what if you only want to bring some order to your model directory? You want to create some subfolders to separate your model physically, if only to avoid having dozens of files in the model folder.

This is where load_missing_constant kicks in again. If you don’t load the files in the subdirectories explicitly, it will assume that the files are in their according namespace. So having a class User in a file user.rb lying in the folder app/models/admin/ will lead it to assume User exists in the module Admin. To avoid that you’ll have to add your model subfolders as load paths. To do that you can add the following line to your environment.rb:

config.load_paths += Dir["#{RAILS_ROOT}/app/models/[a-z]*"]

This will tell Rails to look for the the files in all subfolders of app/models on startup. This won’t solve the issue yet, you’ll still need to explicitly load the classes. So you put the following lines at the end of your environment.rb:

[ "app/models" ].each do |path|
  Dir["#{RAILS_ROOT}/#{path}/**/*.rb"].each do |file|
    load file

That way you’ll avoid the implicit call to load_missing_constant. You can add directories to the list, e.g. a subdirectory in lib. You could also explicitly require the classes you need, but who wants to do that, really?