title: Rails 7 controller decorator uninitialised constant error in production only
body: <p>I am getting the following error <code>zeitwerk/loader/helpers.rb:95:in const_get': uninitialized constant Controllers::BasePublicDecorator (NameError)</code>
  This is an error in a local production console using <code>rails c -e production</code> but not an issue in development which works perfectly.</p>
  <p>In an engine, <code>CcsCms::PublicTheme</code>, I have a decorator I am using to extend the controller of another <code>CcsCms::Core</code> engine and it is this decorator that is causing the error.</p>
  <blockquote>
  <p>public_theme/app/decorators/decorators/controllers/base_public_decorator.rb</p>
  </blockquote>
  <pre><code>CcsCms::BasePublicController.class_eval do
    before_action :set_theme #ensure that @current_theme is available for the
                            #header in all public views
  
    private
  
      def set_theme
        @current_theme = CcsCms::PublicTheme::Theme.current_theme
      end
  end
  </code></pre>
  <p>This functionality is working perfectly in development but fails in production with an error as follows</p>
  <p>The controller I am trying to decorate in the CcsCms::Core engine is CcsCms::BasePublicController.rb</p>
  <pre><code>module CcsCms
    class BasePublicController &lt; ApplicationController
      layout &quot;ccs_cms/layouts/public&quot;
  
      protected
        def authorize
        end
    end
  end
  </code></pre>
  <p>in the theme engine with the decorator I am trying to use I have a Gemfile that defines the core engine as follows</p>
  <pre><code>gem 'ccs_cms_core', path: '../core'
  </code></pre>
  <p>In the ccs_cms_public_theme.gemspec I am requiring the core engine as a dependency</p>
  <pre><code>  spec.add_dependency &quot;ccs_cms_core&quot;
  </code></pre>
  <p>in the engine.rb I am requiring the core engine and loading the decorator paths in a <code>config.to_prepare do</code> block</p>
  <pre><code>require &quot;deface&quot;
  require 'ccs_cms_admin_dashboard'
  require 'ccs_cms_custom_page'
  require 'ccs_cms_core'
  require 'css_menu'
  #require 'tinymce-rails'
  require 'delayed_job_active_record'
  require 'daemons'
  require 'sprockets/railtie'
  require 'sassc-rails'
  
  module CcsCms
    module PublicTheme
      class Engine &lt; ::Rails::Engine
        isolate_namespace CcsCms::PublicTheme
        paths[&quot;app/views&quot;] &lt;&lt; &quot;app/views/ccs_cms/public_theme&quot;
  
        initializer &quot;ccs_cms.assets.precompile&quot; do |app|
          app.config.assets.precompile += %w( public_theme_manifest.js )
        end
  
        initializer :assets do |config|
          Rails.application.config.assets.paths &lt;&lt; root.join(&quot;&quot;)
        end
  
        initializer :append_migrations do |app|
          unless app.root.to_s.match?(root.to_s)
            config.paths['db/migrate'].expanded.each do |p|
              app.config.paths['db/migrate'] &lt;&lt; p
            end
          end
        end
  
        initializer :active_job_setup do |app|
          app.config.active_job.queue_adapter = :delayed_job
        end
  
        config.to_prepare do
          Dir.glob(Engine.root.join(&quot;app&quot;, &quot;decorators&quot;, &quot;**&quot;, &quot;*_decorator*.rb&quot;)) do |c|
            Rails.configuration.cache_classes ? require(c) : load(c)
          end
        end
  
        config.generators do |g|
          g.test_framework :rspec,
            fixtures: false,
            request: false,
            view_specs: false,
            helper_specs: false,
            controller_specs: false,
            routing_specs: false
          g.fixture_replacement :factory_bot
          g.factory_bot dir: 'spec/factories'
        end
  
      end
    end
  end
  </code></pre>
  <p>Given that my decorator is given the same name as the controller it is decorating from the core engine but with the .decorator extension I am pretty certain that is everything hooked up correctly, as mentioned, this works perfectly in development but I am unable to start a rails console in a production environment due to this error.
  It seems that the class_eval is failing somehow and I can only think that this may be a path issue but I can not figure it out</p>
  <p><strong>UPDATE</strong>
  After quite a big learning curve, thank's muchly to @debugger comments and @Xavier Noria
  answer it is clear that my issue comes down to Zeitworks autoload functionality</p>
  <p>Rails guides <a href="https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#config-autoload-once-paths" rel="nofollow noreferrer">here</a>  has an interesting and appealing solution to me</p>
  <blockquote>
  <p>Another use case are engines decorating framework classes:</p>
  </blockquote>
  <pre><code>initializer &quot;decorate ActionController::Base&quot; do  
  &gt; ActiveSupport.on_load(:action_controller_base) do
  &gt;     include MyDecoration   end end
  </code></pre>
  <blockquote>
  <p>There, the module object stored in MyDecoration by the time the
  initializer runs becomes an ancestor of ActionController::Base, and
  reloading MyDecoration is pointless, it won't affect that ancestor
  chain.</p>
  </blockquote>
  <p>But maybe this isn't the right solution, I again failed to make it work with the following</p>
  <pre><code>  initializer &quot;decorate CcsCms::BasePublicController&quot; do
      ActiveSupport.on_load(:ccs_cms_base_public_controller) do
        include CcsCms::BasePublicDecorator
      end
    end
  </code></pre>
  <p>Generating the following error</p>
  <pre><code>zeitwerk/loader/callbacks.rb:25:in `on_file_autoloaded': expected file /home/jamie/Development/rails/comtech/r7/ccs_cms/engines/public_theme/app/decorators/controllers/ccs_cms/base_public_decorator.rb to define constant Controllers::CcsCms::BasePublicDecorator, but didn't (Zeitwerk::NameError)
  </code></pre>
  <p>So back to the solution provided <a href="https://guides.rubyonrails.org/classic_to_zeitwerk_howto.html#decorating-classes-and-modules-from-engines" rel="nofollow noreferrer">here</a>, thank's again for the answer below I tried the following which did work finally</p>
  <pre><code>  config.to_prepare do
      overrides = Engine.root.join(&quot;app&quot;, &quot;decorators&quot;)
      Rails.autoloaders.main.ignore(overrides)
      p = Engine.root.join(&quot;app&quot;, &quot;decorators&quot;)
      loader = Zeitwerk::Loader.for_gem
      loader.ignore(p)
      Dir.glob(Engine.root.join(&quot;app&quot;, &quot;decorators&quot;, &quot;**&quot;, &quot;*_decorator*.rb&quot;)) do |c|
        Rails.configuration.cache_classes ? require(c) : load(c)
      end
    end
  </code></pre>