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 · 3 comments

Comments

Projects
None yet
4 participants
@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 from Problem with rails + rspec + spring + eager_load to rails + rspec + spring + eager_load = uninitialized constant Apr 4, 2017

@drakmail

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment