-
Type: Epic
-
Resolution: Unresolved
-
Priority: Critical - P2
-
None
-
Affects Version/s: None
-
Component/s: Associations
-
None
When an application declares an association, Mongoid must figure out the class of its target. The class may be specified explicitly by the user via the class_name option or it may be unspecified, in which case Mongoid figures it out based on the association name.
Note that what Mongoid needs is the actual class, but what a user specifies, and what Mongoid starts with in the absense of user specification, is the class name. The name may be ambiguous when submodules are involved. For example, in the following definition:
module Foo
class Bar
include Mongoid::Document
has_many :things
end
end
... the things association could refer to the top-level ::Thing or to the Foo::Thing nested under Foo.
An additional complication is that in a Rails application, models are usually autoloaded, meaning in roughly 50% of the cases when the above code executes neither ::Thing nor Foo::Thing have been defined and, importantly, attempting to check whether either is defined could trigger the autoloading of both.
In turn, autoloading comes with its own issue which is described in https://jira.mongodb.org/browse/MONGOID-4750: when a file is being loaded, if the code inside it raises an exception during the loading process, the file would still be considered loaded but only some of the code in it would have been evaluated. Subsequently the exception could be hidden/replaced by a LoadError, thus the original cause of the problem would be lost or, worse, partially loaded code would exist in application with no indication that this happened.
—
AR currently behaves as follows:
- When it encounters an association definition, it tries to obtain the class of the target.
- This may trigger autoloading.
- In turn, this may silently cause the application code to be partially loaded.
Mongoid currently behaves as follows:
- It tries to not look up association classes during association processing (see also https://jira.mongodb.org/browse/MONGOID-4751 where this is explicitly requested).
- It therefore provides better diagnostics when application code is broken and can't be loaded.
- As a consequence, Mongoid does not follow Ruby semantics with respect to name resolution for association targets, as reported in e.g. https://jira.mongodb.org/browse/MONGOID-5080 and elaborated on in https://jira.mongodb.org/browse/MONGOID-5080?focusedCommentId=3737357&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-3737357.
- Because class names are potentially ambiguous, Mongoid could potentially be figuring out association targets incorrectly, or even mapping the same class to multiple different associations (if the same bare name exists in multiple nested modules).
The current Mongoid behavior is making it difficult to work with since the natural and correct thing to do is to compare classes when figuring out association targets but Mongoid has the self-imposed prohibition on such comparisons due to not having the classes available during association processing.
—
Proposed changes in this epic are:
Resolve class names to classes during association processing (i.e. when the association declaration like has_many is being evaluated).
Perform this resolution in the same way Ruby does (look up in the same module first then go up modules to top level)
Add test coverage for class name resolution matching Ruby semantics for embedded and referenced associations, specifically that bare names are looked up in modules first and then on top level
This leaves the issue of partial application code loading. We could recommend a linter task/code snippet to users in our documentation which would load each of their models individually, which would provide diagnostics for when one of the models is broken and unloadable.
- is related to
-
MONGOID-4750 Association definitions can trigger autoloading and cause NameError's
- Closed