We all know Rails has this feature, which reloads source code in development mode everytime a request hits server. Starting from version 3.2.0, it introduced faster dev mode where it reloads application code when the code changes, and not on every request.
This blog will talk about important parts of Rails source code which helps in achieving faster dev mode.
ActiveSupport::FileUpdateChecker
: Checks whether any of the application code files are changed.Activesupport::Dependencies
: Actual module responsible for reloading classes.ActionDispatch::Reloader
: The middleware which helps in reloading classes.reload_classes_only_on_change
: As name states, this configuration option tell Rails to enable/disable code for re-loading classes only if the code changes.
Lets go through them one by one.
ActiveSupport::FileUpdateChecker
This class helps in checking whether application code is updated or not. It exposes
2 methods: updated?
and execute
. The former tells whether files are updated or
not, while latter executes a block given by updating timestamp of latest changed
file. The code can be found here.
How file checker checks whether a file is updated or not depends on the modified
time of the file. There is a small function max_time
which returns timestamp for
recently modified path (most recent one)
ActiveSupport::Dependencies
This module consists of the core mechanism to load classes, by following Rails
naming conventions. It uses const_missing
to catch missing classes, and then
searches in autoload_paths
to load those missing classes. The code can be
found here.
ActionDispatch::Reloader
This is a middleware which provides hooks that can be run while code reloading. It
has 2 callback hooks, :prepare
and :cleanup
. Rails code will make use of these
hooks to install code which determine whether to reload code or not. :prepare
callbacks will run before request is processed, and :cleanup
callbacks will run
after request is processed. You can see call(env)
of reloader here
reload_classes_only_on_change
This configuration option is defined in railties.
By default, it is set to true, so Rails reloads classes only if code changes. Set it
to false, and Rails will reload on each request. Digging into the place where this
boolean is defined, we find that there is an initializer set_clear_dependencies_hook
.
This initializer is defined here.
The above code installs a file watcher if config var is true. watchable_args
consists of autoload_paths
along with other files like schema.rb
. So,
file_watcher
is configured to watch these paths. If config var is false, it
just installs callback as :cleanup
hook, which means all the code will be
unloaded after each request is processed.
How do these components fall in place?
By joining all the dots, the sequence is:
- Request hits the server. The middleware
ActionDispatch::Reloader
kicks in, and executes callbacks inserted - One of the callback inserted is to check whether any application code files have been changed and execute the lambda (shown above which clears dependencies)
- The callback (lambda) will clear all the dependencies, i.e it unloads all the class
constants (by using builtin
remove_const
). - The middleware passes the request down the middleware stack for proper handling. Most probably routes will process the request.
- Once the request handling starts, since all the constants are unloaded, the main
module
ActiveSupport::Dependencies
kicks in, usesconst_missing
and loads all classes once again, thus loading the modified code.
Bonus
If you want to know how routes reloading happens, check this file
Hope you have enjoyed this article, and follow us on twitter
@codemancershq
&bsp;for all the awesome blogs, or you can use rss feeds.