How are files loaded in Rails?

dieutb
3 min readJun 11, 2021

--

Autoload

  • In Ruby, all files need to be loaded (Kernel#load, Kernel#require, Kernel#autoload) in order to have its code run. However, in Rails, we could use autoload_paths to specify the folders and files that need to be loaded automatically.
  • Rails internals make extensive use of it to defer as much work as possible from the boot process. But constant autoloading in Rails is not implemented with Kernel#autoload. One of the reason Rails not using autoload Module#autoload is only capable of loading files using require, so reloading would not be possible.
  • The console autoloads, the test suite autoloads, and of course the application autoloads
  • Don’t use Kernel#require a file in autoload in another autoload file
  • There are some default folders of autoload_paths such as
p ActiveSupport::Dependencies.autoload_pathslib
app/assets
app/controllers
app/helpers
app/jobs
app/mailers
app/models
app/policies
app/serializers
app/services
app/uploaders
app/controllers/concerns
app/models/concerns
test/mailers/previews
  • In Development and Test env,
    + As default, config.cache_classes sets to false, Rails autoloads files with lazyKernel#load and only reload when there’s a change in code. In console mode, need to run reload! command to reload the code.
    + If config.cache_classes sets to true, Rails autoloads files with lazy Kernel#require
  • In Production env, config.cache_classes sets to true as default, Rails autoload with lazy Kernel#require
  • Rails autoloads module/class in files that loaded following the file nameString#camelize and constanceString.underscore. eg:
# 'app/controllers/home_controller.rb', 
# 'home_controller'.camelize is 'HomeController', then the class name would be HomeController. 'HomeController'.underscore => 'home_controller'
class HomeController; end# 'app/models/platform/pock/campaign.rb'
# the constance would be Platform::Pock::Campaign
# 'Platform::Pock::Campaign'.underscore => 'platform/pock/campaign'
# Option1:
module Platform
module Pock
class Campaign
end
end
end
... OR ...
# Option2:
class Platform::Pock::Campaign
end
# Option2, if this is defined in Ruby, there would be an exception error because the module Platform and Platform::Pock aren't defined yet. But in Rails, when a module acts as a namespace, Rails does not require the application to define a file for it, a directory matching the namespace is enough
  • If there is a folder that needs to autoload, just append its path to the config.autoload_paths in the config/environments/[env].rb

Autoload Mechanism

# app/controllers/platform/posts_controller.rb
module Platform
class PostsController < ApplicationController
def index
@posts = Post.all
end
end
end
# *** ApplicationController ***
# If ApplicationController isn't loaded, Rails will autoload it
- At first, rails try to load it inside the namespace Platform: Platform::ApplicationController
#=> app/assets/platform/application_controller.rb
#=> app/controllers/platform/application_controller.rb
#=> [autoload dir]/platform/application_controller.rb
- If there is no ApplicationController inside the Platform namespace, Rails continue load it with no namespace
#=> [autoload dir]/application_controller.rb
- If the ApplicationController is not found, LoadError would be raised "unable to autoload constant ApplicationController"# *** PostsController ***
# If somewhere calls to this (route), even it's not defined, Ruby will just define the controller (no exception raise)
# *** Post ***
- Platform::PostsController::Post

#=> [autoload dir]/platform/posts_controller/post.rb
- Platform::Post
#=> [autoload dir]/platform/post.rb
- Post
#=> [autoload dir]/post.rb

EagerLoad

  • We both know that lazy autoload would help to speed up the time starting the server, but it’s not good for the production’s performance. Because of the fact that Rails support 2 optionseager_load, eager_load_paths to solve this problem by pre-loading all the relevant modules/classes that needed when the server starts
  • eager_load default set to true on production env. There are also some default folders of eager_load_paths such as
p [project namespace]::Application.config.eager_load_pathsapp/assets
app/controllers
app/helpers
app/jobs
app/mailers
app/models
app/policies
app/serializers
app/services
app/uploaders
app/controllers/concerns
app/models/concerns
  • If there is a folder that needs to eager_load, just append its path to the config.eager_load_paths in the config/environments/production.rb

Constant Table and Nested Constant

References

--

--

dieutb
dieutb

Written by dieutb

passion in finding solutions and research some things relate to technical and helpful in life. Also strongly interest in foods, travel, and gentle music :)

No responses yet