janko / rodauth-rails

Rails integration for Rodauth authentication framework
https://github.com/jeremyevans/rodauth
MIT License
565 stars 40 forks source link

uninitialized constant Rodauth::InternalRequestError when eager_load is set to true #288

Closed FelipeBodelon closed 3 months ago

FelipeBodelon commented 3 months ago

Having some issues with using Rodauth's InternalRequestError when eager_load is set to true. My app crashes and can't start correctly.

The issue is present when attempting to rescue from rodauth internal request errors, using internal requests in a controller method.

I'm using Rails version 7.0.3 with ruby 3.2.2 and rodauth-rails 1.13 and rodauth 0.3.3

The code just makes use of said error with a rescue_from block. Haven't really faced an issue like this before, where should I be looking at?

rescue_from Rodauth::InternalRequestError do |e|
    render json: { error: e.message }, status: :unprocessable_entity
end

It seems to be an issue when eager_loading with zeitwerk

2024-04-02T01:12:29.835701+00:00 app[web.1]:   rescue_from Rodauth::InternalRequestError do |e|
2024-04-02T01:12:29.835702+00:00 app[web.1]:                      ^^^^^^^^^^^^^^^^^^^^^^
2024-04-02T01:12:29.835702+00:00 app[web.1]: Did you mean?  InterviewCapsuleDecorator
2024-04-02T01:12:29.835702+00:00 app[web.1]:    from /app/app/controllers/quotations_controller.rb:1:in `<main>'
2024-04-02T01:12:29.835703+00:00 app[web.1]:    from <internal:/app/vendor/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
2024-04-02T01:12:29.835703+00:00 app[web.1]:    from <internal:/app/vendor/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
2024-04-02T01:12:29.835704+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
2024-04-02T01:12:29.835704+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/kernel.rb:30:in `require'
2024-04-02T01:12:29.835704+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/helpers.rb:135:in `const_get'
2024-04-02T01:12:29.835705+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/helpers.rb:135:in `cget'
2024-04-02T01:12:29.835705+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/eager_load.rb:169:in `block in actual_eager_load_dir'
2024-04-02T01:12:29.835705+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/helpers.rb:40:in `block in ls'
2024-04-02T01:12:29.835705+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/helpers.rb:25:in `each'
2024-04-02T01:12:29.835705+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/helpers.rb:25:in `ls'
2024-04-02T01:12:29.835706+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/eager_load.rb:164:in `actual_eager_load_dir'
2024-04-02T01:12:29.835706+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/eager_load.rb:17:in `block (2 levels) in eager_load'
2024-04-02T01:12:29.835724+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/eager_load.rb:16:in `each'
2024-04-02T01:12:29.835724+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/eager_load.rb:16:in `block in eager_load'
2024-04-02T01:12:29.835724+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/eager_load.rb:10:in `synchronize'
2024-04-02T01:12:29.835724+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/eager_load.rb:10:in `eager_load'
2024-04-02T01:12:29.835724+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader.rb:329:in `block in eager_load_all'
2024-04-02T01:12:29.835724+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader.rb:327:in `each'
2024-04-02T01:12:29.835725+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader.rb:327:in `eager_load_all'
2024-04-02T01:12:29.835725+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/railties-7.0.4.3/lib/rails/application/finisher.rb:74:in `block in <module:Finisher>'
2024-04-02T01:12:29.835725+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/railties-7.0.4.3/lib/rails/initializable.rb:32:in `instance_exec'
2024-04-02T01:12:29.835725+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/railties-7.0.4.3/lib/rails/initializable.rb:32:in `run'
2024-04-02T01:12:29.835725+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/railties-7.0.4.3/lib/rails/initializable.rb:61:in `block in run_initializers'
2024-04-02T01:12:29.835725+00:00 app[web.1]:    from /app/vendor/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:228:in `block in tsort_each'
2024-04-02T01:12:29.835726+00:00 app[web.1]:    from /app/vendor/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
2024-04-02T01:12:29.835726+00:00 app[web.1]:    from /app/vendor/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:431:in `each_strongly_connected_component_from'
2024-04-02T01:12:29.835726+00:00 app[web.1]:    from /app/vendor/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:349:in `block in each_strongly_connected_component'
2024-04-02T01:12:29.835726+00:00 app[web.1]:    from /app/vendor/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:347:in `each'
2024-04-02T01:12:29.835726+00:00 app[web.1]:    from /app/vendor/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:347:in `call'
2024-04-02T01:12:29.835726+00:00 app[web.1]:    from /app/vendor/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:347:in `each_strongly_connected_component'
2024-04-02T01:12:29.835726+00:00 app[web.1]:    from /app/vendor/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:226:in `tsort_each'
2024-04-02T01:12:29.835727+00:00 app[web.1]:    from /app/vendor/ruby-3.2.2/lib/ruby/3.2.0/tsort.rb:205:in `tsort_each'
2024-04-02T01:12:29.835727+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/railties-7.0.4.3/lib/rails/initializable.rb:60:in `run_initializers'
2024-04-02T01:12:29.835727+00:00 app[web.1]:    from /app/vendor/bundle/ruby/3.2.0/gems/railties-7.0.4.3/lib/rails/application.rb:372:in `initialize!'
2024-04-02T01:12:29.835727+00:00 app[web.1]:    from /app/config/environment.rb:5:in `<top (required)>'
janko commented 3 months ago

Zeitwerk is likely configured to eager load app/controllers before app/misc. Since Rodauth loads feature files on-demand when enable is called, Rodauth::InternalRequestError will be undefined at the time controllers are being loaded, because enable :internal_request was not yet called on a Rodauth auth class, and lib/rodauth/features/internal_request.rb is the file that defines this error class.

You should be able to fix this by passing the constant name to rescue_from instead of the constant itself, which will remove the requirement that the constant needs to be defined at the time of the rescue_from call.

rescue_from "Rodauth::InternalRequestError" do |e|
  # ...
end