When to_prepare Hook Is Too Late
When I upgraded to Ruby on Rails 6.1, I had to deal with preload problems:
damon@rapthalia:~/oni_sorceress> bin/rails s => Booting Puma => Rails 188.8.131.52 application starting in development => Run `bin/rails server --help` for more startup options Exiting /home/damon/.rbenv/versions/3.0.3/lib64/ruby/gems/3.0.0/gems/actionpack-184.108.40.206/lib/action_dispatch/middleware/stack.rb:144:in `push': can't modify frozen Array: [Webpacker::DevServerProxy, ActionDispatch::HostAuthorization, Rack::Sendfile, ActionDispatch::Static, ActionDispatch::Executor, ActiveSupport::Cache::Strategy::LocalCache::Middleware, Rack::Runtime, Rack::MethodOverride, ActionDispatch::RequestId, ActionDispatch::RemoteIp, Sprockets::Rails::QuietAssets, Rails::Rack::Logger, ActionDispatch::ShowExceptions, WebConsole::Middleware, ActionDispatch::DebugExceptions, ActionDispatch::ActionableExceptions, ActionDispatch::Reloader, ActionDispatch::Callbacks, ActiveRecord::Migration::CheckPending, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ContentSecurityPolicy::Middleware, ActionDispatch::PermissionsPolicy::Middleware, Rack::Head, Rack::ConditionalGet, Rack::ETag, Rack::TempfileReaper] (FrozenError) DEPRECATION WARNING: Initialization autoloaded the constants ApplicationRecord and AnalyticsHttpRequest. 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 ApplicationRecord, for example, the expected changes won't be reflected in that stale Class object. These autoloaded constants have 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. (called from <top (required)> at /home/damon/oni_sorceress/config/environment.rb:5) .........
The problem with
to_prepare hook was that it was too late. I got cannot add middleware to a frozen array error.
I won’t lie, it took me months to fix that, main motivation was upgrade to Ruby on Rails 7.
Fortunately there are more hooks -
before_initialize worked just fine. I have to manually load model file which is used by middleware though.
require Rails.root.join('app', 'models', 'application_record').to_s require Rails.root.join('app', 'models', 'oni_sorceress_record').to_s require Rails.root.join('app', 'models', 'oni_sorceress', 'analytics').to_s require Rails.root.join('app', 'models', 'oni_sorceress', 'analytics', 'request').to_s Rails.configuration.before_initialize do Rails.application.config.middleware.use( RackRequestObjectLogger, ::OniSorceress::Analytics::Request ) end