Trouble with using `packs-rails` and nested directories for `QAnalytics::Destinations` not working with autoloading

This message was imported from the Ruby/Rails Modularity Slack server. Find more info in the import thread.

Hi all. I’m trying to move from self-configured packwerk to using packs-rails but I’m facing some trouble.

This is what I have:

packs/q_analytics/
├── app
│   ├── jobs
│   │   └── q_analytics
│   │       ├── send_data_to_hubspot_job.rb
│   │       └── send_traits_to_hubspot_job.rb
│   └── public
│       ├── q_analytics
│       │   └── tracker.rb
│       └── q_analytics.rb
├── lib
│   └── q_analytics
│       ├── destinations
│       │   ├── base_destination.rb
│       │   ├── hubspot_destination.rb
│       │   └── logger_destination.rb
│       └── destinations.rb
├── package.yml
└── spec
    ├── lib
    │   └── q_analytics
    │       └── destinations
    │           └── hubspot_destination_spec.rb
    └── public
        └── q_analytics
            └── tracker_spec.rb

Contents of packs/q_analytics/app/public/q_analytics.rb:

module QAnalytics
  mattr_accessor :destinations, default: []
end

And packs/q_analytics/lib/q_analytics/destinations.rb contents:

module QAnalytics
  module Destinations
    # Content suppressed for clarity
  end
end

This was my previous custom config which was working fine. I had this in config/application.rb:

config.paths.add "packs", glob: ["*/lib", "*/app/{*,*/concerns}"], eager_load: true

Now I’ve removed that and added packs-rails to my Gempack. It seems to work fine for all my other packs but in the q_analytics pack I have this nested directory “destinations” for QAnalytics::Destinations and rails autoloading doesn’t seem to be working.

To be honest, I think the only reason it worked with my previous config is because of the eager_load: true you can see in that config line above.

This is the error I get:

$ rails c
Running via Spring preloader in process 1965097
Loading development environment (Rails 7.0.4.3)
irb: warn: can't alias context from irb_context.
irb(main):001:0> QAnalytics
=> QAnalytics
irb(main):002:0> QAnalytics::Destinations
(irb):2:in `<main>': uninitialized constant QAnalytics::Destinations (NameError)

But I think this should work with autoloading. What might I’ve be missing? Any ideas?

Just like Rails, packs-rails won’t autoload content that is in a lib folder. Try moving the destinations to app and I suspect it will work.

If, for some reason, you don’t want those folders in app, I believe the best solution is to explicitly require the files.

Given that the package’s code is all about analytics and given the limited info you have shared, I don’t see a reason to keep those files in lib, btw.

You were right. This solved it:

Regarding why these classes are in lib… I think my reasoning was (long ago) these don’t fit on any rails pre-existing categorization.

I know rails doesn’t limit us and we actually have other directories like app/services or app/admin and stuff like that…

I could rename lib as app/destinations I guess.

Moving them to app/models also works without the need for the explicit require, as expected too.

I guess what puzzled me is that it worked with my previous config.

And also, Looking at packs-rails code… I see this and this.

Based on that, it looks like lib is being added to the paths just like any other path. So I thought it would autoload in this case.

But it didn’t :man-shrugging: . I’m obviously missing some detail. But I have enough to move forward for now.

Thanks Stephan!

Message originally sent by slack user U712YWCKK8T

app/lib is a common directory used for code that doesn’t fit any Rails standard folder, though more specific names like app/destinations I think are better

I agree with using app/lib which is kind of the “accepted solution”. Here Andrew White and Xavier Noria say it https://github.com/rails/rails/issues/37835#issuecomment-560075069

just FYI https://github.com/rails/rails/pull/48572