heartcombo / devise

Flexible authentication solution for Rails with Warden.
http://blog.plataformatec.com.br/tag/devise/
MIT License
23.83k stars 5.53k forks source link

`parent_mailer` config option boot error #5663

Closed eneagoe closed 6 days ago

eneagoe commented 6 months ago

Environment

Current behavior

Setting up the parent_mailer options with

config.parent_mailer = "ApplicationMailer"

prevents the application from starting up - there's a class loading issue, apparently:

=> Booting Puma
=> Rails 7.1.2 application starting in development
=> Run `bin/rails server --help` for more startup options
Exiting
~/.rvm/gems/ruby-3.2.2@webapp/gems/activesupport-7.1.2/lib/active_support/inflector/methods.rb:290:in `constantize': uninitialized constant ApplicationMailer (NameError)

      Object.const_get(camel_cased_word)
            ^^^^^^^^^^
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/activesupport-7.1.2/lib/active_support/core_ext/string/inflections.rb:74:in `constantize'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/devise-4.9.3/app/mailers/devise/mailer.rb:4:in `<main>'
    from <internal:~/.rvm/rubies/ruby-3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
    from <internal:~/.rvm/rubies/ruby-3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/bootsnap-1.17.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/zeitwerk-2.6.12/lib/zeitwerk/kernel.rb:38:in `require'
    from ~/webapp/config/initializers/devise_mailers.rb:1:in `<main>'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/engine.rb:683:in `load'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/engine.rb:683:in `block in load_config_initializer'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/activesupport-7.1.2/lib/active_support/notifications.rb:208:in `instrument'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/engine.rb:682:in `load_config_initializer'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/engine.rb:636:in `block (2 levels) in <class:Engine>'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/engine.rb:635:in `each'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/engine.rb:635:in `block in <class:Engine>'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/initializable.rb:32:in `instance_exec'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/initializable.rb:32:in `run'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/initializable.rb:61:in `block in run_initializers'
    from ~/.rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:228:in `block in tsort_each'
    from ~/.rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
    from ~/.rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:422:in `block (2 levels) in each_strongly_connected_component_from'
    from ~/.rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:431:in `each_strongly_connected_component_from'
    from ~/.rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:421:in `block in each_strongly_connected_component_from'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/initializable.rb:50:in `each'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/initializable.rb:50:in `tsort_each_child'
    from ~/.rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:415:in `call'
    from ~/.rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:415:in `each_strongly_connected_component_from'
    from ~/.rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:349:in `block in each_strongly_connected_component'
    from ~/.rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:347:in `each'
    from ~/.rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:347:in `call'
    from ~/.rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:347:in `each_strongly_connected_component'
    from ~/.rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:226:in `tsort_each'
    from ~/.rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:205:in `tsort_each'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/initializable.rb:60:in `run_initializers'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/application.rb:423:in `initialize!'
    from ~/webapp/config/environment.rb:5:in `<main>'
    from config.ru:3:in `require_relative'
    from config.ru:3:in `block in <main>'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/rack-3.0.8/lib/rack/builder.rb:103:in `eval'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/rack-3.0.8/lib/rack/builder.rb:103:in `new_from_string'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/rack-3.0.8/lib/rack/builder.rb:94:in `load_file'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/rack-3.0.8/lib/rack/builder.rb:64:in `parse_file'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/rackup-2.1.0/lib/rackup/server.rb:354:in `build_app_and_options_from_config'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/rackup-2.1.0/lib/rackup/server.rb:263:in `app'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/rackup-2.1.0/lib/rackup/server.rb:424:in `wrapped_app'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/commands/server/server_command.rb:76:in `log_to_stdout'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/commands/server/server_command.rb:36:in `start'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/commands/server/server_command.rb:145:in `block in perform'
    from <internal:kernel>:90:in `tap'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/commands/server/server_command.rb:136:in `perform'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/thor-1.3.0/lib/thor/command.rb:28:in `run'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/thor-1.3.0/lib/thor/invocation.rb:127:in `invoke_command'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/command/base.rb:178:in `invoke_command'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/thor-1.3.0/lib/thor.rb:527:in `dispatch'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/command/base.rb:73:in `perform'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/command.rb:71:in `block in invoke'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/command.rb:149:in `with_argv'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/command.rb:69:in `invoke'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/railties-7.1.2/lib/rails/commands.rb:18:in `<main>'
    from <internal:~/.rvm/rubies/ruby-3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
    from <internal:~/.rvm/rubies/ruby-3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:38:in `require'
    from ~/.rvm/gems/ruby-3.2.2@webapp/gems/bootsnap-1.17.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
    from bin/rails:6:in `<main>'

Trying to get around this issue by defining the class in config/initializers/devise.rb with something like

class ApplicationMailer < ActionMailer::Base
end

will start the app correctly, but it won't work as expected - none of the before actions defined in app/mailers/application_mailer.rb will apply.

Expected behavior

Setting up parent_mailer should at the very least not crash the booting process.

ebihara-tomonari commented 6 days ago

Hi @eneagoe , I've encountered a similar error. In the error, there is the following statement.

from ~/webapp/config/initializers/devise_mailers.rb:1:in `<main>'

Actually, isn't the definition like this?

class Devise::Mailer < Devise.parent_mailer.constantize
  include Devise::Mailers::Helpers

  def confirmation_instructions(record, token, opts = {})
    @token = token
    devise_mail(record, :confirmation_instructions, opts)
  end

  # and another override for mailer etc.
end

And then, you should these override in custom mailer. Please refer to the documentation ( https://github.com/heartcombo/devise/wiki/How-To:-Use-custom-mailer ) as well. So you should remove config/initializers/devise_mailers.rb.

config/application.rb is like this,

Devise.setup do |config|
  ...

  config.mailer = "MyMailer"

  config.parent_mailer = "ApplicationMailer"
end
eneagoe commented 6 days ago

Thank you @ebihara-tomonari but the link you mention is referring to using a custom mailer, not a parent mailer. This seems to be a class loading issue - the defined parent mailer class is not loaded so Devise::Mailer crashes because it can't find its base class.

ebihara-tomonari commented 6 days ago

@eneagoe Yeah, I know that. But, your devise_mailers.rb probably customize like custom mailer, and use parent_mailer in the end.

And your error occured config/initializers/devise_mailers.rb, not ~config/application.rb~ config/initializers/devise.rb. That why config.parent_mailer = "ApplicationMailer" in ~config/application.rb~ config/initializers/devise.rb is no problem. So I think, if you remove config/initializers/devise_mailers.rb, rails command don't occur error at least.

You should check config/initializers/devise_mailers.rb. And, if you customize Devise::Mailer in devise_mailers.rb, you should customize with custom mailer.

ebihara-tomonari commented 6 days ago

I'm so sorry 🙇 not config/application.rb, config/initializers/devise.rb is correct!

eneagoe commented 6 days ago

Thank you, I think I figured out the issue indeed, you pointed me in the right direction - the culprit was the devise_mailers.rb: if I move that custom setup into the config.mailer class the app correctly starts, and parent_mailer is also correctly configured.

I'm going to close this one, thank you again for the help!