Uploaded image for project: 'Mongoid'
  1. Mongoid
  2. MONGOID-4802

Test eagerly loading application classes in rake tasks that use Mongoid.models with Rails 6/zeitwerk / create_index rake task

    • Type: Icon: Improvement Improvement
    • Resolution: Fixed
    • Priority: Icon: Minor - P4 Minor - P4
    • 7.1.4
    • Affects Version/s: 7.0.5
    • Component/s: None
    • Labels:
      None
    • Environment:
      Mac Catalina, ruby 2.6.5

      Rails 6/zeitwerk appears to have changed behavior with respect to eagerly loading classes. This seems to apply at a minimum to rake tasks that depend on :environment.

      In Rails 5.2, when a rake task depending on :environment is run (such as db:mongoid:create_indexes), ::Mongoid.models is populated with (seemingly all of) the models defined by the application.

      In Rails 6, ::Mongoid.models is empty in the same scenario.

      Interestingly, in Rails 5.2 ::Mongoid.models appears to be empty if one executes a Rails console, therefore it appears that eager loading of application classes is configured based on what script/tool/command is invoked and not just which environment is used.

      In https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#eager-loading which describes behavior of Rails 6 with zeitwerk, eager loading of classes is claimed to only happen in production environment:

      > Eager loading is controlled by the flag config.eager_load, which is enabled by default in production mode.

      This change means that, for example, when one runs rake db:mongoid:create_indexes, Mongoid thinks there are no models defined in the application and as a result it does not create any of the indexes defined by the user.

      To reproduce this issue one must have an application created with Rails 6, such as https://github.com/mongoid/mongoid-demo/tree/master/rails.

      An application that depends on Rails 6 but uses Rails 5.2 defaults gets the classic autoloader and does not exhibit the issue described herein.

      Proposed workaround per the comment:

      config.autoloader = :classic
      

      The fix appears to run this prior to referencing ::Mongoid.models:

      Zeitwerk::Loader.eager_load_all 
      

      However, this needs to be conditioned on zeitwerk actually being used as the application's dependency loader.

      Todo:

      Identify code using Mongoid.models - appears to only be Rake tasks in Mongoid source
      Add documentation to Mongoid.models explaining that the model classes must be loaded before they are seen in this list, pointing out the behavior differences between Rails 5 and Rails 6
      Add calls to eagerly load all models to Mongoid's rake tasks
      (optional) Add an application reproducing the issue as a test case (cf. https://jira.mongodb.org/browse/MONGOID-4661)

            Assignee:
            oleg.pudeyev@mongodb.com Oleg Pudeyev (Inactive)
            Reporter:
            martin@wulffeld.org Martin Wulffeld
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: