Love using dry-system but I’ve come across what I believe is a load order issue and wondering how others deal with it. I’m currently adding the graphql gem to my plain ruby project. The structure is like this
Resolvers are what actions a graphql query, and the types are just objects with whatever fields (very similar to a dry-struct actually)
Inside a resolver class are the types that will be used for the specific query. Defined like this
type Types::User, null: true
description "Returns a user for the specified user id"
What I find is every time I boot my application I get the following exception:
NameError: uninitialized constant Types::User
This is because it tries to load the resolvers first, hits the line where the type is defined and can’t figure it out as the types were not loaded first. I can fix this by requiring the type classes at the top of the file but that doesn’t seem right. Isn’t one of the benefits of dry system the fact that I shouldn’t have to require a bunch of files at the top of each class?
when I rename the types folder to apple, they get loaded first, so I have no issue with booting. This is obviously not an ideal workaround. I’ve actually had to do this for other graphql classes and put them in a folder called grapql/zebra to be loaded last, when ideally they shouldn’t need to be in a folder at all. In the meantime I will go back to requiring necessary files at the top of a class, but would love a better resolution, or just a better understanding if this is the way it is.
Tried to be as verbose as possible, let me know if more information is required. Thanks.
I don’t know the answer in general for
dry-system, but in this specific case you can just avoid the issue by just giving a string to the
type method. GraphQL-ruby will resolve the class name later on, when all classes are loaded. So change your line to:
type 'Types::User', null: true
What I think you want here is a simple
require "types/user" at the top of your resolver file.
It’s important to remember that dry-system’s auto-registration functionality is intended as a way to fill your container with registrations based on the files in your source directories. While it does so happen to
require those files as part of completing that job, requiring the files is not its primary purpose.
Our recommendation for people using dry-system is to “require what you require”. So if you’re needing to access some piece of code (i.e. refer to a constant, in your case,
Types::User) that is not an injected dependency, you should require it explicitly. This is especially important for you to be able to resolve a registration from a non-finalized container (when auto-registration hasn’t run) and have everything work as it should. This is the kind of thing you’d do when running your tests.
Let me know if that all makes sense
Oh, if your types classes aren’t intended to be injectable registrations, you also probably also want to ensure they don’t get auto-registered in the container. I suspect that if you ran
MyContainer.keys, you’d see they’re all there. One way to do this is to put the
# auto_register: false magic comment at the top of the file.
Thanks for the explanation, this makes a lot of sense! Didn’t know about the auto register comment either so that’ll come in handy.
@MicMicMon thanks, nice little tip for this specific scenario