Typically, you use require
to load libraries and modules your Ruby code needs.
require 'net/http'
The Ruby interpreter loads the required code as soon as it comes across the require
method.
However, often you may not want to load all the dependencies as soon as possible. If they take a long time to load, it can slow down your application initialization process. This is really important during local development and also when running tests. You want to load, run, and test the app as quickly as possible, without loading any code that you won't use.
In these cases, to speed up the initialization process, Ruby provides the autoload
method that lazily loads the specified modules. In addition, Rails overrides and abundantly uses this method to set up various sub-frameworks like ActiveModel and ActiveStorage, etc.
The first time I came across autoloading, I was pretty baffled, as I hadn't seen something like that in C# and JavaScript. After a little bit of digging, it turned out to be a simple and pretty useful concept.
So, what does the autoload
method do, and how does it work?
Let's try to understand Ruby's version first.
Autoloading in Ruby
The autoload
method takes two arguments: Module Name (can be either a string or a symbol) and filename (string). It registers the filename to be loaded the first time that module is accessed.
autoload :Payment, '/lib/modules/payment.rb'
What it means is that Rails won't load the payment.rb
script until you actually need it. It will only load it when you first use the Payment
module in your codebase.
Using autoload
allows you to speed up the initialization of your library by lazily loading the modules that your code depends on. It won't load the library or framework code you don't need.
Autoloading in Rails
Ruby on Rails provides its own autoload
method via its Active Support framework. It allows you to load modules based on Rails naming conventions, by automatically guessing the filename based on the module name.
module ActiveModel
extend ActiveSupport::Autoload
# autoload this module from the
# active_model/secure_password.rb file
autoload :SecurePassword
end
In this example, Rails will look for the SecurePassword
module in the active_model/secure_password.rb
file.
Here's the simplified implementation of this method in Rails.
def autoload(const_name, path)
unless path
full = [name, const_name.to_s].compact.join("::")
path = Inflector.underscore(full)
end
super const_name, path
end
If the path
is not provided, Rails guesses the path by joining the constant name with the current module name and generating its underscored and lowercase form. Finally, it calls Ruby's autoload
method by calling super
and passes the module name and the generated path.
For example, consider the following code:
module ActiveModel
extend ActiveSupport::Autoload
autoload :API
autoload :Name, "active_model/naming"
end
The first time you use the API
module, Rails will load it from active_model/api.rb
file. In contrast, when you need the Name
class, it will be loaded from the active_model/naming.rb
file.
Autoloading Multiple Modules From the Same Directory
If multiple modules live under a common folder structure, you can also use the autoload_under
helper.
module ActionController
extend ActiveSupport::Autoload
autoload :API
autoload :Base
autoload_under "metal" do
autoload :Cookies
audoload :Flash
end
end
The Cookies
and Flash
modules will be loaded from action_controller/metal/{cookies/flash}.rb
files.
Autoloading Multiple Modules in the Same File
If a single file contains multiple modules that you want to autoload, use the autoload_at
helper. For example, the action_view/buffers.rb
file contains two modules: OutputBuffer
and StreamingBuffer
. To autoload them both, Rails uses the following code:
module ActionView
extend ActiveSupport::Autoload
autoload_at "action_view/buffers" do
autoload :OutputBuffer
autoload :StreamingBuffer
end
end
Eager Load Modules As Necessary
Finally, you can also define a set of modules that need to be eager loaded using the eager_autoload
method.
class Cipher
extend ActiveSupport::Autoload
eager_autoload do
autoload :Aes256Gcm
end
end
Then you can eager load the Aes256Gcm
module by calling the eager_load!
method (notice the !
bang)
Cipher.eager_load!
The original implementation of the eager_load!
method looped through the modules marked to be eager loaded and simply required them as follows:
def eager_load!
@_autoloads.each_value { |file| require file }
end
However, in the latest version of Rails, it's using the const_get
method to load the constants, see this PR for more details.
Anyway, that's all for now. If you're curious to learn the difference between load
, autoload
, require
, and require_relative
methods, check out this article:
I hope you liked this article and you learned something new.
As always, if you have any questions or feedback, didn't understand something, or found a mistake, please leave a comment below or send me an email. I look forward to hearing from you.
If you'd like to receive future articles directly in your email, please subscribe to my blog. If you're already a subscriber, thank you.