wessman.co

Published on

Rails 6.1 - Zeitwerk warnings for Clearance and Omniauth

Author

Everytime my Sidekiq process started, I was met with these errors:

WARN: DEPRECATION WARNING: Initialization autoloaded the constants ConfirmedUserGuard, ApplicationHelper, EmailHelper, ApplicationController, and OauthController.
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 ConfirmedUserGuard, 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.

A large blob of text with specific warnings for:

  • ConfirmedUserGuard
  • ApplicationHelper
  • EmailHelper
  • ApplicationController
  • OauthController

I have not had a lot of experience with Zeitwerk before this but started reading the Autoloading and Reloading Constants from the Rails guides.

Learning by guides like this is not my strong suite, so I tried to get more specific.

Clearance

I noticed that one of the objects listed in the warning was ConfirmedUserGuard, this is a very Clearance-specific object and only used once in config/initializers/clearance.rb.

Clearance is the authentication library I am using in the application. I got Github-jackpot with clearance#842, the configurations needs to be passed as strings instead.

Before: config/initializers/clearance.rb

# frozen_string_literal: true

Clearance.configure do |config|
  config.mailer_sender = '<my-name>@wessman.co'
  config.rotate_csrf_on_sign_in = true
  config.routes = false
  config.allow_sign_up = true
  config.sign_in_guards = [ConfirmedUserGuard]
end

After - config/initializers/clearance.rb

# frozen_string_literal: true

Clearance.configure do |config|
  config.mailer_sender = '<my-name>@wessman.co'
  config.rotate_csrf_on_sign_in = true
  config.routes = false
  config.allow_sign_up = true
  config.sign_in_guards = %w[ConfirmedUserGuard]
end

I wrote a little tweet about memorizing %w vs %i.

%w[] will give you an array of words: w == word.

Omniauth

The othe warnings were very general, for example ApplicationHelper and ApplicationController.

OauthController is more specific and only referenced once in my app.

I stumbled onto another Github issue on Rails itself: rails/rails#35978.

The final comment, for helping all the googlers:

thanks, raising would be ideal. here is the bit of code that works for people coming from google:

 OmniAuth.config.on_failure = Proc.new do |env|
   OauthController.action(:failure).call(env)
 end

and it solved my problem!

Before: config/initializers/omniauth.rb before

# frozen_string_literal: true

Rails
  .application
  .config
  .middleware
  .use(OmniAuth::Builder) do
    provider(:developer) unless Rails.env.production?
    github = Rails.application.credentials.github
    if github.present?
      provider(
        :github,
        github[:client_id],
        github[:client_secret],
        scopes: 'user:email,repo:status'
      )
    end
  end

OmniAuth.config.on_failure = OauthController.action(:oauth_failure)
OmniAuth.config.logger = Rails.logger

After: config/initializers/omniauth.rb

# frozen_string_literal: true

Rails
  .application
  .config
  .middleware
  .use(OmniAuth::Builder) do
    provider(:developer) unless Rails.env.production?
    github = Rails.application.credentials.github
    if github.present?
      provider(
        :github,
        github[:client_id],
        github[:client_secret],
        scopes: 'user:email,repo:status'
      )
    end
  end

OmniAuth.config.on_failure = proc do |env|
  OauthController.action(:oauth_failure).call(env)
end
OmniAuth.config.logger = Rails.logger

Conclusion

It turned out that OauthController loaded ApplicationController and the other helpers, so by fixing that one there are no more warnings.

Now we can run bin/rails zeitwerk:check to make sure we are in good shape!

Loading a Rails application with all its dependencies seems like a very hard problem and I think the Rails-team have done a tremendous job with Zeitwerk and hopefully we can all help to document and improve the libraries we use.