In a Rails 6 app without ActionMailer included (rails new testapp --skip-action-mailer), the default zeitwerk loader errors when eager-loading due to mailers/devise/mailer.rb not defining Devise::Mailer. Output from rails zeitwerk:check:
expected file /usr/local/bundle/gems/devise-4.7.1/app/mailers/devise/mailer.rb to define constant Devise::Mailer,
Zeitwerk eager-loading should work without ActionMailer. Suggested options:
Idiomatically, you want to ignore that file. It could done with something like this in Devise (off the top of my head):
initializer "devise.configure_zeitwerk_if_enabled" do
if Rails.autoloaders.zeitwerk_enabled? && !defined?(ActionMailer)
Rails.autoloaders.main.ignore("#{__dir__}/relative/path/to/devise/mailer.rb")
end
end
@fxn I would only add a check for Rails::Version::MAJOR >= "6" so it does not break on older versions of Rails where the method zeitwerk_enabled? does not exist, wdyt?
Oh yes, totally.
In case others come here in search for a quick solution:
It's possibly to work around the issue by simply adding ActionMailer in config/application.rb along with the other frameworks:
require "action_mailer/railtie"
For what it's worth, in a Rails 6.0.1 app without the ActionMailer railtie, it seems that defining Devise::Mailer as an empty class does not break anything. The app sends emails via a 3rd party service.
# <path-to-gems>/devise-4.7.1/app/mailers/devise/mailer.rb
if defined?(ActionMailer)
class DeviseMailer < Devise.parent_mailer.constantize
# whatever was already there
end
else
class DeviseMailer
end
end
Tested authentication, registration, validation, forgot password flows.
Obviously inferior solution to explicitly ignoring the file in an initializer, but thought I'd share.
Hi everyone, I'm working on this and I was wondering how can I write a test to check whether the file has been ignored or not please as I don't have an in-depth Rails API knowledge ?
This is what I added so far (else statement) :
if defined?(ActionMailer)
class Devise::Mailer < Devise.parent_mailer.constantize
# whatever was already there
else
if Rails::Version::MAJOR >= "6"
Rails.autoloaders.main.ignore("#{__dir__}/relative/path/to/devise/mailer.rb")
end
end
Thank you for your help.
Out of curiosity, why _isn't_ the preferred solution here simply for Devise to start using "zeitwerk-correct" file structure and class naming?
Most helpful comment
In case others come here in search for a quick solution:
It's possibly to work around the issue by simply adding ActionMailer in
config/application.rbalong with the other frameworks: