dukehenry
dukehenry

Reputation: 31

Zeitwerk and Namespacing STI Models

I am trying to figure out an issue I am having with my rails app that involves namespacing some sti models.

Originally, I had a collection of sti models located in: app/models/foo I validated these models against json schemas located in app/models/schemas I tested these models from specs in spec/models/foo with factories from spec/factories/foo

My primary model Primary (from which the sti models are linked) did have a method that points to the schemas directory to load everything up.

As is, all is well.

However, I figured I would do something "simple" and move my schemas into a categorized subdirectory to match that of the models, specs, and factories. Seemed like a smart idea.

So, I imagined that I would need to figure out a way to take my sti models, and derive a way to generate the proper path for the schemas so that it looks in the right directory based on its category. For now, I have bar, but in the future I plan on adding baz and qux.

Searching online, it seemed like the first/easiest solution is to namespace the models. That way I can pull that namespace to generate the directory name in my method to point at the json schema path. At least, that is the idea. I don't get far enough to try this out.

So, I namespace one of my models:

module Foo
class Bar < ::Primary
..
end

which matches my file structure (models/foo/bar.rb)

But when I try to check my Zeitwerk or enter a console I get the error: expected file /../app/models/foo/bar.rb to define constant Bar, but didn't.

I was reading online and found solutions that involved creating a foo.rb file in my app/models directory containing a empty module for Foo, but that didn't work either.

(The Zeitwerk documentation seems to imply that this file is not needed)

Specifically, the documentation says (in explicit namespaces):

Classes and modules that act as namespaces can also be explicitly defined, though. For instance, consider

app/models/hotel.rb -> Hotel app/models/hotel/pricing.rb -> Hotel::Pricing

There, app/models/hotel.rb defines Hotel, and thus Zeitwerk does not autovivify a module.

The classes and modules from the namespace are already available in the body of the class or module defining it:

class Hotel < ApplicationRecord include Pricing # works ... end

So, according to the error, Zeitwerk is expecting bar.rb to define constant Bar, but didn't. If I explicitly create the definition - Bar = Foo::Bar then everything works. However, this seems like something isn't right. I would imagine from the documentation that this shouldn't be needed.

I get that technically, Bar is not being explicitly defined (as it is contained within the module Foo) but the documentation seems to point to that format.Obviously, I am missing something.

So, I guess I am looking for clarification on how I should be namespacing these models to get them to work. Or, should I not even attempt to namespace the models and use a different approach to allow for me to match the file structure of the json schemas to that of my models/specs/factories instead of dumping everything in one directory?

For what it is worth, I am using Rails 7.0.8.4. I did see that Rails 7.1x seems to have improved namespace support for core directories like /lib but I don't know if upgrading to 7.1x would make any difference.

Upvotes: 1

Views: 123

Answers (0)

Related Questions