I just ran into this issue as well. I had defined an ApplicationController inside my engine and was seeing NoMethodErrors when I tried to use helper methods inside one of my engine's controllers.
The Problem
The code looked something like this:
in my_engine/app/controllers/my_engine/application_controller.rb
module MyEngine
class ApplicationController < ActionController::Base
helper ApplicationHelper
end
end
in my_engine/app/controllers/my_engine/projects_controller.rb
module MyEngine
class ProjectsController < ApplicationController
def new
# some action code here
end
end
end
in my_engine/app/helpers/my_engine/application_helper.rb
module MyEngine
module ApplicationHelper
def translations_include_tag
javascript_include_tag "translations-#{I18n.locale}.js"
end
end
end
If I navigated to a route in the host rails app, then clicked a link that navigated to my_engine/projects/new, I would get a NoMethodError saying translations_include_tag didn't exist.
The Explanation
I think this was happening because the application had two classes with the same name: ApplicationController in MyEngine and ApplicationController in the host app. When the first route outside the engine is visited, Rails autoloads the ApplicationController from the host app. What that means is Rails associates the main app's ApplicationController with the name "ApplicationController". When you navigate to my_engine/projects/new, Rails lazy loads ProjectsController which also inherits from ApplicationController. Rails/ruby thinks you're referring to the same ApplicationController it has already loaded, so in effect ProjectsController ends up inheriting from the host app's ApplicationController instead of the one in the engine. Since the translations_include_tag method isn't defined in the host app's ApplicationController, ruby raises a NoMethodError when the view tries to call it.
The Solution
I was able to fix the problem by explicitly inheriting from MyEngine's ApplicationController:
in my_engine/app/controllers/my_engine/projects_controller.rb
module MyEngine
# changed from just plain 'ol ApplicationController
class ProjectsController < ::MyEngine::ApplicationController
def new
# some action code here
end
end
end
After fixing the inheritance issue, the NoMethodError went away.
The accepted answer says to use eager loading, which will also fix the problem because it forces the engine's ApplicationController to load first. Since the engine's ApplicationController is namespaced inside MyEngine, it's full name is MyEngine::ApplicationController, which doesn't conflict with the main app's ApplicationController because the constant names are different.