Quickfix: Zeitwerk loading error with devise when no ActionMailer is defined

(en)

rails

There is more information that you can read about it in Devise's Issues page.

But what happened to us is that we added Devise to make authentication, but we won't be using ActionMailer so we didn't include it. And now Zeitwerk complains.

So, what's going on?

The file devise/mailers/mailer.rb starts like this:


if defined?(ActionMailer)
class Devise::Mailer < Devise.parent_mailer.constantize
include Devise::Mailers::Helpers

...
end
end

So the file will only get defined when ActionMailer is defined and available. So no, Devise::Mailer class is exposed and Zeitwerk complains.

Some solutions go about detecting if Zeitwerk is loading and just then adding an empty class. Kind of like so:


elsif Zeitwerk.is_loading?
class Devise::Mailer; end
end

I argue that we shouldn't be adding more dependencies into the file, just leave an empty class so Zeitwerk doesn't complain about the file's output but also leaves us with a simpler solution.

Maybe a better way to solve it is to add the methods if ActionMailer is defined

class Devise::Mailer < Devise.parent_mailer.constantize
if defined?(ActionMailer)
# Add the methods here
end
end

But that's a discussion for the gem's maintainers. For now, what we did is to define ActionMailer on an initializer.

config/initializers/devise.rb

module ActionMailer
class Base; end
end

And that solve it, we are still verifying is that is a stable solution, but for now, we can't find any trouble with the patch, which allow us to think that the proposed way of fixing the gem can also be the best.