autoloading in Rails
02 Sep 2016using non-standard directories in Rails project (lib/, system/, etc.).
autoload_paths and eager_load_paths
- http://urbanautomaton.com/blog/2013/08/27/rails-autoloading-hell
- http://blog.arkency.com/2014/11/dont-forget-about-eager-load-when-extending-autoload
by default only subdirectories of app/ are added to autoload_paths
and
eager_load_paths
(the latter is used in environments with eager loading -
staging or production).
other directories (say, lib/) added manually to autoload_paths
are not
added to eager_load_paths
automatically - it’s necessary to do it explicitly
in config/application.rb:
config.autoload_paths += Dir["#{config.root}/lib/**/"]
config.eager_load_paths += Dir["#{config.root}/lib"]
the same in one go (note it’s not necessary to add all nested directories):
config.paths.add 'lib', eager_load: true
not adding them to eager_load_paths
not only causes performance issues
(classes inside lib/ are lazy loaded in production) but also might be the
source of weird uninitialized constant errors.
to sum up always add non-standard directories to both autoload_paths
and eager_load_paths
to avoid loading errors in production.
using modules to namespace classes
2 ways to organize code in non-standard directories:
-
always use fully qualified class names:
class Forms::Google::Adwords::Config < Reform::Form ...
this allows to avoid loading problems but might be very inconvenient when class has a lot of modules and inherits from another class with the same amount of modules. also this way requires to use fully qualified names when referencing other classes from inside class definition.
-
nest class name inside modules:
module Forms module Google module Adwords class Config < Reform::Form ...
note if project has some class with
Config
module you must inline it (use it as a part of class name):module Operations module Google module Adwords class Config::Create < Operations::Base ...
since otherwise:
module Operations module Google module Adwords module Config class Create < Operations::Base ...
Rails might complain that
Config
is not a class if it loadsOperations::Google::Adwords::Config::Create
first and knows thatConfig
is a module but later you try to define it as a class.in some cases when top-level modules don’t overlap you can type them side by side:
module Persistence::Repositories module Google module Adwords class Configs < Base[:google_adwords_configs] ...
also controller classes are loaded fine without nesting:
class Google::Adwords::ConfigsController < ApplicationController ...