This is related to my post from yesterday, but approaching the issue differently:
Given the massive breakages with module configuration and loading, between Rails 6 and Rails 7, and big change in loaders from classic to Zeitwerk, what is the new way of organizing models and modules?
I need to have models loaded in models/foo/bar.rb on boot.
How do I configure bar.rb, config/application.rb and Zeitwerk, to autoload “class Bar” in Rails 7.1.x and 7.2.x ?
Code from 6.1 is now breaking, where I previously abided by this nesting:
module Foo
class Bar
Stuff
end
end
I was also referencing the above from controller and elsewhere with Foo::Bar.new()
Nesting one level deeper than that was also possible…
Rails 7.2 does not seem to load models in subdirectories of models/extras
require ‘foo/bar’ no longer works, but did work in v6.
please help! “everything” is miserably and mysteriously broken! (the paths and nested references)
I made some progress – but it is actually a retrogress
I made my old Rails 6.1 modules and their naming work again, without editing the files containing them, simply by switching back to the 6.1 load_defaults in application.rb
config.load_defaults 6.1
To make it work I also had to get rid of my "config.autoload_paths << “#{Rails.root}/app/models/foo” lines (mentioned previously) in application.rb .
When I add the full directory path (“models/foo”) to config.autoload_paths, the loader does load those files but does not construct the reference “Foo::Bar”.
(“Foo::Bar.new()”) throws an error as a nonexistent reference)
The loader treats model files in models/foo as top-level classes/modules (top level namespace), and does not build the “Foo::Bar” reference. Even with load_defaults 6.1
When you remove the full path, the 6.1 defaults do their classic thing
Questions:
The original question: What is the proper way to do the naming in 7.1 ?
What am I forfeiting and/or risking by reverting to the 6.1 load_defaults at this point?
EDIT: I have come to like the classic convention – helps better organize one’s modules… and track them… where the directory structure/hierarchy is reflected in Rails object the reference… The references themselves remind you where things are.
You do not need to add autoload paths for anything within /app. /app/* are in the autoload path already. By adding app/models/foo to the autoload path, you are instructing zeitwerk to then look for app/models/foo/foo/bar.rb to find Foo::Bar.
Going from there, you would have to share the actual error messages you are receiving to be able to help you resolve them. Also, is there a particular reason for auto-loading this specific model?
I installed a new instance of Rails 7.2.2.1, since the time I posted here, and used a different boot configuration, with application.rb, etc. – less cluttered and closer to install defaults. Zeitwerk is quiet – not even sure if it’s engaged.
The problem with Foo::Bar.new is no longer there. The reason this was important was that this is a rails upgrade, for an existing Rails app, with existing code that implements the models/foo/bar.rb => Foo::Bar.new constructs
Would have had to rename all the references, and I wasn’t sure if the renaming was mandatory or not. So now, apparently, 7.2.2.1 behaves like the old 6.1…
Everything under app/models doesn’t need to be added into any “load paths” configurations, as long as your directories are modules.
app/models/foo/bar.rb expects class Foo::Bar.
app/models/foo/bar/baz.rb expects class Foo::Bar::Baz
and so on
If you add a sub-directory of app/models into autoload paths, then it becomes the new “starting directory” for rails. This could be useful if you specifically don’t want the directory to become a namespace.
For example, you could do this:
config.autoload_paths << 'app/models/reports'
And then create: app/models/reports/monthly_report.rb. Because the reports directory is now considered one of the “base directories”, the class must be without a namespace: class MonthlyReport.
However, if you are going to do that, I recommend putting this kind of directory directly under app.
app/reports/monthly_report.rb
With this approach you don’t need to mess with autoload_paths at all. Any directory under app/ automatically becomes a “base directory” in which all files are expected without namespaces.