Read more

Heads up: Byebug has problems with zeitwerk

Avatar
Judith Roth
May 12, 2021Software engineer at makandra GmbH

I encountered a unlucky behavior of byebug 11.1.3 (the most recent version at time of writing) when using it with Rails 6 and it's new autoloading component, zeitwerk. There already is a issue Archive for that, so I hope it will be fixed with a future release.

Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more

The following test succeeds:

  context 'factories' do
    let(:test_case) { FactoryBot.create(:test_case) }
    it 'are valid' do
      expect(test_case).to be_valid
    end
  end

But when I did the same in byebug the following happened:

(byebug) FactoryBot.create(:test_case)
*** NameError Exception: uninitialized constant #<Class:0x000055580a8e7918>::TargetLimitation
Did you mean?  TargetsTestScenario

It seems like Byebug does not work well with zeitwerk. There is already a patch in Ruby 3.1 Archive , that would allow Byebug to solve the issue. But at the time of writing only ruby/debug Archive implemented the fix and uses TracePoint.allow_reentry. The issue for Byebug Archive is still open.

Solutions

Good: Use a different debugger

Jard Archive seems also to have problems with zeitwerk, since the create statement just didn't return.
Pry Archive (binding.pry) worked without problems for me. Note: In case you are using pry-byebug, you need to replace it with pry. Otherwise binding.pry is still broken.

Neutral: Use eager loading in tests

Eager loading means all classes are loaded before the code starts executing. Be aware that this could have an impact on the performance of tests.

config/environments/test.rb:

config.eager_load = true

Bad: Switch back to use the classic autoloading

config/application.rb:

config.autoloader = :classic

Your choice of debugger should not force you to use old/different settings in the whole application. You can do that temporarily though.

Even more bad: explicitly require the not found class

This will leave you with a mess of requires that has to be maintained and be cleaned up in the future. You can do that temporarily though.

Also quite bad: Explicitly mention the class before your debugger statement

# ... (code)
TestCase::TargetLimitation
debugger
# ... (more code)

This will leave you with a mess of calls to the class that has to be maintained and be cleaned up in the future. You can do that temporarily though.

Posted by Judith Roth to makandra dev (2021-05-12 09:31)