Replace auto_register! by component_dirs.add

Hello ! I’m trying to upgrade to the latest version of dry_rails (which comes with latest version of dry_system) and I’m having troubles with the update of auto_register! into config.component_dirs.add 'smth' . I was in 0.3.0 for dry_rails and i’m trying to upgrade to 0.5.0. The register was like this:

Dry::Rails.container do
  ...
  auto_register!('app/event_sourcing')
  ...
end

and now:

Dry::Rails.container do
  ...
  config.component_dirs.add 'app/event_sourcing'
  ...

but it still breaks all my tests. Am i missing something ? Is there something else to change ?
By the way, the add in component_dirs return this:

config.component_dirs.add 'app/event_sourcing'
=> #<Dry::System::Config::ComponentDir:0x000055e15988ef88
 @config=
  #<Dry::Configurable::Config values={:auto_register=>true, :instance=>nil, :loader=>Dry::System::Loader, :memoize=>false, :namespaces=>#<Dry::System::Config::Namespaces:0x000055e15988e970 @namespaces={}>, :add_to_load_path=>true}>,
 @path="app/event_sourcing">

So it looks like it works but I don’t know what else to do.
Thank you for your help!

Can you share a little more detail about what, specifically, is going wrong?

Well, i’m using rails event store in my app, and every ReadEvents isn’t launching anymore. But I just saw that we use register() method to add them(?) into dry config. Maybe I also need to replace these methods by something else ?
Example:
register(:event_store, RailsEventStore::Client.new)

I just investigated a bit more and the problem is that in this code in the start step of my provider:

start do
  Read::ApplicationProjection.descendants.each do |projection|
    event_store.subscribe(
      projection, to: projection.subscribed_events
    )
  end
end

The line Read::ApplicationProjection.descendants returns an empty array. I have the following tree:

> app
  > event_sourcing
    > read
      application_projection.rb
      > titles
        ...all descendants are here...

So maybe the config.component_dirs.add 'app/event_sourcing' doesn’t add the descendants properly? I am a litte lost here

Is it possible that you switched from standard require loading to autoloading?

In my configuration, my container entries are lazy-instantiated using the Zeitwerk plugin. This speeds up boot time in development and testing, but a side-effect of autoloading is that the constants for your code don’t exist until you reference them (or resolve the corresponding container key).

Take a look at component_dirs["app/event_sourcing"].loader.ancestors. In my case I can see that Dry::System::Loader::Autoloading is an ancestor of the component loader.

Another potential way to tell is that the zeitwerk plugin adds config.autoloader

descendants is problematic when used in combination with autoloading. You have to reference the constants first before they will appear in the list.

The Zeitwerk changelog suggests iterating constants in the namespace to preload them in situations like this.

Thanks for your answer but unfortunately no, I do not have autoloading :confused: this is the output of ancestors:

> config.component_dirs["app/event_sourcing"].loader.ancestors
=> [Dry::System::Loader,
 ActiveSupport::Dependencies::ZeitwerkIntegration::RequireDependency,
 ActiveSupport::ForkTracker::CoreExtPrivate,
 ActiveSupport::ForkTracker::CoreExt,
 ActiveSupport::ToJsonWithActiveSupportEncoder,
 Object,
 Minitest::Expectations,
 PP::ObjectMixin,
 ActiveSupport::Dependencies::Loadable,
 ActiveSupport::Tryable,
 JSON::Ext::Generator::GeneratorMethods::Object,
 Kernel,
 BasicObject]

and config.autoloader returns undefined method error.
So the fix would be tu use Zeitwerk and configure the loader to preload every constants i need ?
Thank you!

This may look a little different in dry-rails compared to me, since I am using dry-system without Rails.

Rails uses Zeitwerk autoloading for everything in app/ so I believe that your missing descendants is happening because your provider’s start step is running before Zeitwerk is loading the classes you need.

You might consider moving those out of app/ and into lib/, and requiring them in the prepare step to ensure that they exist in the object system. Downside to that approach is that you don’t get hot reloading with them anymore, but I’m uncertain if that works with your event subscriptions anyway.

I should’ve added the dry-rails tag indeed, but this was working before the upgrade and I didn’t changed a thing expect from upgrading to new version so I can’t see another reason that the upgrade to cause empty descendants. Was there a loading of some sort in previous versions removed in the newest version ? I’ll try using zeitwerk in the container like you suggested maybe that’ll help