In a Rails initializer, I assign additional application configuration as follows:
module MyApp
class Application
config.x.email = {
default: '[email protected]',
invoice: '[email protected]'
}
end
end
Recently, however, I had to introduce a value object class for those email addresses to encapsulate some logic needed to properly align with SPF/DKIM/DMARC:
module MyApp
class Application
config.x.email = {
default: EmailAddress.new('[email protected]'),
invoice: EmailAddress.new('[email protected]')
}
end
end
On Rails 6.1, this triggers a warning:
DEPRECATION WARNING: Initialization autoloaded the constant EmailAddress.
Being able to do this is deprecated. Autoloading during initialization is going
to be an error condition in future versions of Rails.
Reloading does not reboot the application, and therefore code executed during
initialization does not run again. So, if you reload EmailAddress, for example,
the expected changes won’t be reflected in that stale Class object.
This autoloaded constant has been unloaded.
In order to autoload safely at boot time, please wrap your code in a reloader
callback this way:
Rails.application.reloader.to_prepare do
# Autoload classes and modules needed at boot time here.
end
That block runs when the application boots, and every time there is a reload.
For historical reasons, it may run twice, so it has to be idempotent.
Check the "Autoloading and Reloading Constants" guide to learn more about how
Rails autoloads and reloads.
I'm not sure how to follow this advice in this particular spot.
As a workaround, adding require "email_address"
to the top of the initializer gets rid of the warning, but it's not really solving the issue at its core.
Any ideas how to tackle this?
Thanks for your help!
You have to wrap the whole config part in to_prepare
block:
# config/initializers/email_config.rb
Rails.application.reloader.to_prepare do
Rails.application.config.x.email = {
default: EmailAddress.new("[email protected]"),
invoice: EmailAddress.new("[email protected]")
}
end
You can also put your email_address.rb
in lib
directory and just require it, once you figure out all the behaivor for EmailAddress
you won't really need it to be reloadable. Restart will be required if you make any changes to EmailAddress
in this case:
# config/initializers/email_config.rb
require "email_address" # => loads lib/email_address.rb
Rails.application.config.x.email = {
default: EmailAddress.new("[email protected]"),
invoice: EmailAddress.new("[email protected]")
}
Another option is to have email_address.rb
in autoload_once_paths
, which is the same as requiring it but without the require
:
# config/application.rb
config.autoload_once_paths << Rails.root.join("app/value_objects")
# config/initializers/email_config.rb
# EmailAddress will be loaded from app/value_objects/email_address.rb only once
Rails.application.config.x.email = {
default: EmailAddress.new("[email protected]"),
invoice: EmailAddress.new("[email protected]")
}