Skip to content
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

rails + rspec + spring + eager_load = uninitialized constant #519

Open
radarek opened this issue Apr 4, 2017 · 6 comments
Open

rails + rspec + spring + eager_load = uninitialized constant #519

radarek opened this issue Apr 4, 2017 · 6 comments

Comments

@radarek
Copy link

@radarek radarek commented Apr 4, 2017

When I set eager_load = true in config/environments/test.rb then after spring is loaded and any file is changed then running specs again will fail with a message like "uninitialized constant User (NameError)".

I created simple rails project repository to reproduce it: https://github.com/radarek/rails_rspec_spring_eager_load_bug. It's pure rails project. I added only gems rspec-rails and spring-commands-rspec and generated User model. When I run bin/rspec specs pass, running it again still gives success. But after modifying app/models/user.rb file and running it again it will fail with a message user_spec.rb:3:in <top (required)>': uninitialized constant User (NameError)`.

I know that doesn't have to be a problem with spring itself but it's hard to guess what it causes.

Steps to reproduce:

$ git clone git@github.com:radarek/rails_rspec_spring_eager_load_bug.git
$ cd rails_rspec_spring_eager_load_bug
$ bin/rails db:migrate RAILS_ENV=test
$ bin/rspec
Running via Spring preloader in process 81040
.

Finished in 0.00345 seconds (files took 0.38525 seconds to load)
1 example, 0 failures
$ bin/rspec
Running via Spring preloader in process 81140
.

Finished in 0.00326 seconds (files took 0.3545 seconds to load)
1 example, 0 failures
$ echo "# comment" >> app/models/user.rb
$ bin/rspec
Running via Spring preloader in process 81305
/Users/radarek/programming/github/radarek/rails_rspec_spring_eager_load_bug/spec/models/user_spec.rb:3:in `<top (required)>': uninitialized constant User (NameError)
	from /Users/radarek/.rbenv/gems/2.4.0/gems/rspec-core-3.5.4/lib/rspec/core/configuration.rb:1435:in `load'
	from /Users/radarek/.rbenv/gems/2.4.0/gems/rspec-core-3.5.4/lib/rspec/core/configuration.rb:1435:in `block in load_spec_files'
	from /Users/radarek/.rbenv/gems/2.4.0/gems/rspec-core-3.5.4/lib/rspec/core/configuration.rb:1433:in `each'
	from /Users/radarek/.rbenv/gems/2.4.0/gems/rspec-core-3.5.4/lib/rspec/core/configuration.rb:1433:in `load_spec_files'
	from /Users/radarek/.rbenv/gems/2.4.0/gems/rspec-core-3.5.4/lib/rspec/core/runner.rb:100:in `setup'
	from /Users/radarek/.rbenv/gems/2.4.0/gems/rspec-core-3.5.4/lib/rspec/core/runner.rb:86:in `run'
	from /Users/radarek/.rbenv/gems/2.4.0/gems/rspec-core-3.5.4/lib/rspec/core/runner.rb:71:in `run'
	from /Users/radarek/.rbenv/gems/2.4.0/gems/rspec-core-3.5.4/lib/rspec/core/runner.rb:45:in `invoke'
	from /Users/radarek/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rspec-core-3.5.4/exe/rspec:4:in `<top (required)>'
	from /Users/radarek/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-commands-rspec-1.0.4/lib/spring/commands/rspec.rb:18:in `load'
	from /Users/radarek/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-commands-rspec-1.0.4/lib/spring/commands/rspec.rb:18:in `call'
	from /Users/radarek/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-2.0.1/lib/spring/command_wrapper.rb:38:in `call'
	from /Users/radarek/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-2.0.1/lib/spring/application.rb:191:in `block in serve'
	from /Users/radarek/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-2.0.1/lib/spring/application.rb:161:in `fork'
	from /Users/radarek/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-2.0.1/lib/spring/application.rb:161:in `serve'
	from /Users/radarek/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-2.0.1/lib/spring/application.rb:131:in `block in run'
	from /Users/radarek/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-2.0.1/lib/spring/application.rb:125:in `loop'
	from /Users/radarek/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-2.0.1/lib/spring/application.rb:125:in `run'
	from /Users/radarek/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/spring-2.0.1/lib/spring/application/boot.rb:19:in `<top (required)>'
	from /Users/radarek/.rbenv/versions/2.4.0/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require'
	from /Users/radarek/.rbenv/versions/2.4.0/lib/ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:in `require'
	from -e:1:in `<main>'
@radarek radarek changed the title Problem with rails + rspec + spring + eager_load rails + rspec + spring + eager_load = uninitialized constant Apr 4, 2017
@drakmail
Copy link

@drakmail drakmail commented Jul 10, 2017

I have almost same problem, but rspec throws error even on second run without modifying any files. I faced with this problem after enabling eager_loading for test environment

@lime
Copy link

@lime lime commented Nov 30, 2017

Apparently this is due to Rails 5 disabling autoloading (and thus auto-reloading) of constants when config.eager_load = true.

However, thanks to this article I learned that it's possible to re-enable that behaviour using config.enable_dependency_loading = true. From the Rails guides:

config.enable_dependency_loading: when true, enables autoloading, even if the application is eager loaded and config.cache_classes is set as true. Defaults to false.

With that line added to test.rb, your reproduction steps start working again. :) Thanks for creating the sample app!

@timdiggins
Copy link

@timdiggins timdiggins commented Jan 22, 2018

@radarek @lime An alternative to enable_dependency_loading is to just turn eager_load off: https://github.com/timdiggins/rails_rspec_spring_eager_load_bug/tree/no-eager-loading.

It doesn't AFAICT gain anything to turn eager_load on (despite the very old (2012) message about turning it on when using a pre-loader (spring) in the generated config: https://github.com/rails/rails/blame/master/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt#L12 rails/rails@e6747d8).
Reading the history of https://github.com/rails/spring/blame/master/lib/spring/application.rb has helped, but this is mostly very old (older than the changes to eager_load)

However I'm still working through this approach in practice. It may mean you need to explicitly spring stop more often. Alternatively it might mean you need to set cache_classes = false (and there might be a performance hit if so).

luigi added a commit to codeforamerica/michigan-benefits that referenced this issue Feb 17, 2018
luigi added a commit to codeforamerica/michigan-benefits that referenced this issue Feb 20, 2018
luigi added a commit to codeforamerica/michigan-benefits that referenced this issue Feb 21, 2018
luigi added a commit to codeforamerica/michigan-benefits that referenced this issue Feb 22, 2018
@thaohoangc3
Copy link

@thaohoangc3 thaohoangc3 commented May 19, 2020

I find that config.enable_dependency_loading sometimes not work correctly. If autoloading has been working fine for you, then the most straighforward and run in predictable manner is diffing the eager_load_paths and auto_load_paths and add the diff to eager_load_paths. That's what I do in my project with external engines and unconventional code locations.

@thaohoangc3
Copy link

@thaohoangc3 thaohoangc3 commented May 19, 2020

 load_disparities = (ActiveSupport::Dependencies.autoload_paths - config.eager_load_paths).uniq
 config.eager_load_paths += load_disparities unless Rails.env.development?

I prefer to keep autoload in test to true, to keep cfg between test and prod the same

@chriscz
Copy link

@chriscz chriscz commented Nov 24, 2020

I'm using minitest in a Rails engine and encountered a similar issue. None of the proposed solutions worked for me. I found that adding my autoload paths to ActiveSupport::Dependencies.autoload_paths did work for me:

ActiveSupport::Dependencies.autoload_paths += [
  File.absolute_path(File.join(__dir__, 'support/'))
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants