railsadminteam / rails_admin

RailsAdmin is a Rails engine that provides an easy-to-use interface for managing your data
MIT License
7.89k stars 2.25k forks source link

Avoid eager loading Turbo Ruby files #3687

Closed jdufresne closed 3 months ago

jdufresne commented 3 months ago

Some projects use RailsAdmin without using Turbo or ActionCable. In these applications, when the Rails configuration option config.eager_load is set to true, the RailsAdmin requirement of turbo will result in eager loading files that can't load.

The result is the following error:

.../vendor/bundle/ruby/3.3.0/gems/turbo-rails-2.0.5/app/channels/turbo/streams_channel.rb:34:in `<top (required)>': uninitialized constant ActionCable (NameError)

class Turbo::StreamsChannel < ActionCable::Channel::Base
                              ^^^^^^^^^^^
Did you mean?  ActionMailer
    from /home/jon/.rubies/ruby-3.3.2/lib/ruby/3.3.0/bundled_gems.rb:74:in `require'
    from /home/jon/.rubies/ruby-3.3.2/lib/ruby/3.3.0/bundled_gems.rb:74:in `block (2 levels) in replace_require'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/kernel.rb:26:in `require'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/loader/helpers.rb:139:in `const_get'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/loader/helpers.rb:139:in `cget'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/loader/eager_load.rb:175:in `block in actual_eager_load_dir'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/loader/helpers.rb:42:in `block in ls'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/loader/helpers.rb:25:in `each'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/loader/helpers.rb:25:in `ls'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/loader/eager_load.rb:170:in `actual_eager_load_dir'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/loader/eager_load.rb:17:in `block (2 levels) in eager_load'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/loader/eager_load.rb:16:in `each'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/loader/eager_load.rb:16:in `block in eager_load'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/loader/eager_load.rb:10:in `synchronize'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/loader/eager_load.rb:10:in `eager_load'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/loader.rb:413:in `block in eager_load_all'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/loader.rb:411:in `each'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/loader.rb:411:in `eager_load_all'
    from .../vendor/bundle/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/application/finisher.rb:80:in `block in <module:Finisher>'
    from .../vendor/bundle/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/initializable.rb:32:in `instance_exec'
    from .../vendor/bundle/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/initializable.rb:32:in `run'
    from .../vendor/bundle/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/initializable.rb:61:in `block in run_initializers'
    from /home/jon/.rubies/ruby-3.3.2/lib/ruby/3.3.0/tsort.rb:231:in `block in tsort_each'
    from /home/jon/.rubies/ruby-3.3.2/lib/ruby/3.3.0/tsort.rb:353:in `block (2 levels) in each_strongly_connected_component'
    from /home/jon/.rubies/ruby-3.3.2/lib/ruby/3.3.0/tsort.rb:434:in `each_strongly_connected_component_from'
    from /home/jon/.rubies/ruby-3.3.2/lib/ruby/3.3.0/tsort.rb:352:in `block in each_strongly_connected_component'
    from /home/jon/.rubies/ruby-3.3.2/lib/ruby/3.3.0/tsort.rb:350:in `each'
    from /home/jon/.rubies/ruby-3.3.2/lib/ruby/3.3.0/tsort.rb:350:in `call'
    from /home/jon/.rubies/ruby-3.3.2/lib/ruby/3.3.0/tsort.rb:350:in `each_strongly_connected_component'
    from /home/jon/.rubies/ruby-3.3.2/lib/ruby/3.3.0/tsort.rb:229:in `tsort_each'
    from /home/jon/.rubies/ruby-3.3.2/lib/ruby/3.3.0/tsort.rb:208:in `tsort_each'
    from .../vendor/bundle/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/initializable.rb:60:in `run_initializers'
    from .../vendor/bundle/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/application.rb:426:in `initialize!'
    from .../config/environment.rb:7:in `<top (required)>'
    from /home/jon/.rubies/ruby-3.3.2/lib/ruby/3.3.0/bundled_gems.rb:74:in `require'
    from /home/jon/.rubies/ruby-3.3.2/lib/ruby/3.3.0/bundled_gems.rb:74:in `block (2 levels) in replace_require'
    from .../vendor/bundle/ruby/3.3.0/gems/zeitwerk-2.6.14/lib/zeitwerk/kernel.rb:34:in `require'
    from .../vendor/bundle/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/application.rb:402:in `require_environment!'
    from .../vendor/bundle/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/command/actions.rb:20:in `boot_application!'
    from .../vendor/bundle/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/commands/console/console_command.rb:105:in `perform'
    from .../vendor/bundle/ruby/3.3.0/gems/thor-1.3.1/lib/thor/command.rb:28:in `run'
    from .../vendor/bundle/ruby/3.3.0/gems/thor-1.3.1/lib/thor/invocation.rb:127:in `invoke_command'
    from .../vendor/bundle/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/command/base.rb:178:in `invoke_command'
    from .../vendor/bundle/ruby/3.3.0/gems/thor-1.3.1/lib/thor.rb:527:in `dispatch'
    from .../vendor/bundle/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/command/base.rb:73:in `perform'
    from .../vendor/bundle/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/command.rb:71:in `block in invoke'
    from .../vendor/bundle/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/command.rb:149:in `with_argv'
    from .../vendor/bundle/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/command.rb:69:in `invoke'
    from .../vendor/bundle/ruby/3.3.0/gems/railties-7.1.3.4/lib/rails/commands.rb:18:in `<top (required)>'
    from /home/jon/.rubies/ruby-3.3.2/lib/ruby/3.3.0/bundled_gems.rb:74:in `require'
    from /home/jon/.rubies/ruby-3.3.2/lib/ruby/3.3.0/bundled_gems.rb:74:in `block (2 levels) in replace_require'
    from bin/rails:4:in `<main>'

As a workaround, my application requires ActionCable, but it doesn't actually use it.

Removing the eager loading, does not remove using Turbo in the frontend. There is no change there.

coveralls commented 3 months ago

Coverage Status

coverage: 95.97% (+0.02%) from 95.947% when pulling 0c2cdb3eb2a465964b87cc361522b7ee1d25f745 on jdufresne:eager-turbo into 91737ab3c2fa22cbe08aedd28770a12704fde6c7 on railsadminteam:master.

mshibuya commented 3 months ago

This was already addressed in turbo-rails. https://github.com/hotwired/turbo-rails/issues/512 Please wait for the next release of it, or use the github source:

gem 'turbo-rails', github: 'hotwired/turbo-rails'
jdufresne commented 3 months ago

Thanks for that link! Will do.

Can you explain why the require 'turbo-rails' exists in Rails Admin if it is only used in JavaScript? What is that for? As we see here, removing it doesn't cause a test to fail, so maybe we would benefit from a new test to demonstrate.

mshibuya commented 3 months ago

It's necessary for asset pipeline configuration. Without it assets:precompile fails.

% rails assets:precompile
bin/rails aborted!
Sprockets::FileNotFound: couldn't find file 'turbo' with type 'application/javascript' (Sprockets::FileNotFound)
...