Reload! does not work well with autoload

I use Rails 6.0.4 with classic autoloader on Ruby 2.7.

With following code, I found referencing A::B::C::D::E_VARIANT1 in fresh rails console works fine. However, after reload! ing in console, A::B::C::D::E_VARIANT1 began to fail:

NameError: uninitialized constant A::B::C::D::E_VARIANT1

How can I fix this?

app/models/a/b/c.rb

module A::B::C
  module D
    extend ActiveSupport::Autoload

    autoload_at 'a/b/c/d/e' do
      autoload :E_VARIANT1
      autoload :E_VARIANT2
    end
  end
end

app/models/a/b/c/d/e.rb

module A
  module B
    module C
      module D
        class E; end
        class E_VARIANT1 < E; end
        class E_VARIANT2 < E; end
      end
    end
  end
end

There is no easy solution for that, because Module#autoload uses Kernel#require and therefore is idempotent.

In your project, A::B::C::D::E is an autoloadable constant, and A::B::C::D::E_VARIANT1 is not, but usage does not seem to even refer to ...::E.

You could technically mutate $LOADED_FEATURES in a to_prepare callback, but starts to feel too hacky perhaps.

The easiest way to make this flow with autoloading is to define a file for each constant, either at the same level, or nested (A::B::C::D::E::VARIANT1), and let things autoload by themselves without that extra configuration.

1 Like

There’s a another option.

If you throw

module A
  module B
    module C
      module D
        class E; end
        class E_VARIANT1 < E; end
        class E_VARIANT2 < E; end
      end
    end
  end
end

into app/models/a/b/c/d.rb, then you don’t need Module#autoload either, and everything autoloads and reloads just fine (because in order to reach any E you have first to pass necessarily through A::B::C::D, which loads d.rb, which defines the child constants as a side-effect).

Both proposed solutions work in zeitwerk mode as well.

1 Like

Actually, E is relatively large class and variants are 6 kinds of a three-line class. So I wanted to put anything related to variants into e.rb.

It looks like things are not so easy than I thought. As you suggested, making file for each variants respectively fixed my problem. Thank you.