Skip to content

Rails::Application in Rails::Engine.descendants causing undefined method 'root' error during Spring v4.3.0 preloading #737

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
aaronskiba opened this issue Mar 27, 2025 · 3 comments

Comments

@aaronskiba
Copy link

Observation:

When using Spring v4.3.0 with Rails v7.1.5.1, the following error is encountered during preloading when starting the rails console:

$ bin/spring stop && rails c
Spring is not running
/usr/share/rvm/gems/ruby-3.0.5@dmp/gems/railties-7.1.5.1/lib/rails/railtie.rb:228:in `method_missing': undefined method `root' for Rails::Application:Class (NoMethodError)
        from /usr/share/rvm/gems/ruby-3.0.5@dmp/gems/spring-4.3.0/lib/spring/application.rb:128:in `block in preload'
        from /usr/share/rvm/gems/ruby-3.0.5@dmp/gems/spring-4.3.0/lib/spring/application.rb:127:in `each'
        from /usr/share/rvm/gems/ruby-3.0.5@dmp/gems/spring-4.3.0/lib/spring/application.rb:127:in `preload'
        from /usr/share/rvm/gems/ruby-3.0.5@dmp/gems/spring-4.3.0/lib/spring/application.rb:176:in `serve'
        from /usr/share/rvm/gems/ruby-3.0.5@dmp/gems/spring-4.3.0/lib/spring/application.rb:158:in `block in run'
        from /usr/share/rvm/gems/ruby-3.0.5@dmp/gems/spring-4.3.0/lib/spring/application.rb:152:in `loop'
        from /usr/share/rvm/gems/ruby-3.0.5@dmp/gems/spring-4.3.0/lib/spring/application.rb:152:in `run'
        from /usr/share/rvm/gems/ruby-3.0.5@dmp/gems/spring-4.3.0/lib/spring/application/boot.rb:25:in `<top (required)>'
        from <internal:/usr/share/rvm/rubies/ruby-3.0.5/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
        from <internal:/usr/share/rvm/rubies/ruby-3.0.5/lib/ruby/3.0.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
        from -e:1:in `<main>'

The error occurs in the Spring preloader, specifically when iterating through Rails::Engine.descendants in the Spring application boot process (see line 127 in the Spring code).

Debugging

The following modification to the Spring preloader code reveals which engine(s) do not respond to the root method:

if defined?(Rails) && Rails.application
  watcher.add Rails.application.paths["config/initializers"]
  Rails::Engine.descendants.each do |engine|
    if !engine.respond_to?(:root)
      puts "#{engine} does not respond to root"
    elsif engine.root.to_s.start_with?(Rails.root.to_s)
      watcher.add engine.paths["config/initializers"].expanded
    end
  end
  watcher.add Rails.application.paths["config/database"]
  if secrets_path = Rails.application.paths["config/secrets"]
    watcher.add secrets_path
  end
end

Running this revealed the following output:

$ bin/spring stop && rails c
Spring is not running
Rails::Application does not respond to root
Running via Spring preloader in process 2199565
Loading development environment (Rails 7.1.5.1)
3.0.5 :001 > 

Cause

The issue arises because Rails::Application is part of Rails::Engine.descendants, but it does not respond to the root method as other Rails engines do. This results in the NoMethodError when Spring tries to call root on it.

Suggested Solution

Modify the Spring preloader code to check if the engine responds to root before calling it. Specifically, update the block that iterates through Rails::Engine.descendants as follows:

Rails::Engine.descendants.each do |engine|
  if engine.respond_to?(:root) && engine.root.to_s.start_with?(Rails.root.to_s)
    watcher.add engine.paths["config/initializers"].expanded
  end
end

This ensures that Rails::Application (and any other engines that do not respond to root) are safely excluded from the root method call.

@aaronskiba
Copy link
Author

After reinstalling the ruby version, reinstalling rvm, and switching over to rbenv, I still experienced the same issue. However, another developer on my team was successful in using Spring v4.3.0 with the same codebase on their machine.

@atfrase
Copy link

atfrase commented May 12, 2025

I just encountered this as well while updating an application to Rails 7.0.8.7. One similarity I notice is that I'm also still on Ruby 3.0 (3.0.1 in my case), and updating that to 3.1.7 seemed to avoid the issue as well. Unfortunately I can't update Ruby on my server just yet, so instead I've downgraded Spring to 4.2.1 for now.

stejskalleos added a commit to stejskalleos/foreman that referenced this issue May 13, 2025
Spring v4.3.0, in combination with Ruby 3.0.7 and Rails 7,
is causing an error that blocks the Rails start.

Error: method_missing: undefined method root
for Rails::Application:Class (NoMethodError)

One solution could be to upgrade Ruby to 3.1.7,
but that doesn't work on the latest Fedora 42 [1].

And upgrading to 3.2.z is not feasible due to some gems
limiting Ruby versions to < 3.2 (safe-render, I think).

External issues:
[0] rails/spring#737
[1] rbenv/ruby-build#2529
@ekohl
Copy link

ekohl commented May 13, 2025

Just for context: ActiveSupport patches descendants different on Ruby < 3.1 and >= 3.1, at least on Rails < 7.2 (which dropped Ruby < 3.1 support):
https://github.com/rails/rails/blob/a6722a964fc647592c0f831fcae43203339823e5/activesupport/lib/active_support/core_ext/class/subclasses.rb#L7-L29

I suspect that the native Ruby implementation yields a slightly different result where one does return Rails::Application and the other doesn't.

stejskalleos added a commit to stejskalleos/foreman that referenced this issue May 13, 2025
Spring v4.3.0, in combination with Ruby 3.0.7 and Rails 7,
is causing an error that blocks the Rails start.

Error: method_missing: undefined method root
for Rails::Application:Class (NoMethodError)

One solution could be to upgrade Ruby to 3.1.7,
but that doesn't work on the latest Fedora 42 [1].

And upgrading to 3.2.z is not feasible due to some gems
limiting Ruby versions to < 3.2 (safe-render, I think).

External issues:
[0] rails/spring#737
[1] rbenv/ruby-build#2529
ofedoren pushed a commit to theforeman/foreman that referenced this issue May 13, 2025
Spring v4.3.0, in combination with Ruby 3.0.7 and Rails 7,
is causing an error that blocks the Rails start.

Error: method_missing: undefined method root
for Rails::Application:Class (NoMethodError)

One solution could be to upgrade Ruby to 3.1.7,
but that doesn't work on the latest Fedora 42 [1].

And upgrading to 3.2.z is not feasible due to some gems
limiting Ruby versions to < 3.2 (safe-render, I think).

External issues:
[0] rails/spring#737
[1] rbenv/ruby-build#2529
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants