Plugin development: A copy of ApplicationController has been removed from the module tree but is still active!

I get this error non-stop when developing. It used to only happen after around ~8 pages, but now it’s happening after around 1-3. The error looks like this:

The blurred text is the name of the module for my plugin

Note how the name is, confusingly (and by my design), ApplicationsController. This shouldn’t be important since I’ve been having this issue long before this controller existed.

I believe this is related to rails code reloading, and shouldn’t have to do with your naming. Something like the following happens:

  • You start the app
  • It loads up the core .rb files and stores the resultant classes into constants (like ApplicationController)
  • Those classes refer to other classes, which are then loaded into constants in the same way (like BaseController if you have ApplicationsController < BaseController)
  • These classes are singletons, meaning only one of them exists in the world, and are uniquely referred to by their class name. Rails keeps track of which constants you’ve defined and loads them automatically when you reference them.

Rails also automatically re-defines most of these constants when you change things. So, if you change the code for BaseController, rails will automatically determine that constant is stale, refresh the definition from your code, as well as any classes referencing that file (so, ApplicationsController will be reloaded as well to account for the new reference to BaseController)

This works great, until you are dealing with classes which are not hot reloaded. A common example with a typical rails app is putting things into the lib directory (rather than the app directory), which are not automatically reloaded by default. So this situation arises when you have a file in /lib which references a file in /app, the /app file is changed, but the /lib file is not, leaving it pointing to a class which has been removed from the list of classes defined in the rails app.

I’ve run into this as well very occasionally with Discourse in the past, but didn’t have the gumption to troubleshoot it too hard. But, as a start, I believe you have a case where some of your plugin code is not being reloaded (maybe something needs to be added to autoload_paths?), and is breaking when it references some constant which is hot reloaded.

7 Likes

Thanks a lot for the response.

None of my Ruby backend code has ever restarted when I made a change, so I suspect you’re right. I also don’t think this happens when I turn cache_classes to true. I’ll see if adding it to autoload_paths fixes it, thanks!

Did you ever solve this?

This should not happen anymore now that we migrated to Zeitwerk. If it is still happening what is the exact repro?

Running Discoure stable branch in Docker in development with a custom plugin. Refreshing the page a few times causes this issue and then I have to restart the server.

Aha, well we have a new stable coming out next month. Current state you have is very temporary with a workable albeit annoying workaround.

2 Likes