Я тоже только что столкнулся с этой проблемой. Я определил ApplicationController
внутри своего движка и видел NoMethodError
, когда пытался использовать вспомогательные методы внутри одного из контроллеров моего движка.
Проблема
Код выглядел примерно так:
в my_engine/app/controllers/my_engine/application_controller.rb
module MyEngine
class ApplicationController < ActionController::Base
helper ApplicationHelper
end
end
в my_engine/app/controllers/my_engine/projects_controller.rb
module MyEngine
class ProjectsController < ApplicationController
def new
# some action code here
end
end
end
в 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
Если бы я перешел к маршруту в приложении host rails, а затем щелкнул ссылку, ведущую к my_engine/projects/new, я бы получил NoMethodError
, говорящий, что translations_include_tag
не существует.
Объяснение
Я думаю, это происходило потому, что в приложении было два класса с одинаковыми именами: ApplicationController
в MyEngine
и ApplicationController
в хост-приложении. При посещении первого маршрута вне движка Rails автоматически загружает ApplicationController
из хост-приложения. Это означает, что Rails связывает ApplicationController
основного приложения с именем «ApplicationController». Когда вы переходите к my_engine/projects/new, Rails отложенно загружает ProjectsController
, который также наследуется от ApplicationController
. Rails/ruby считает, что вы имеете в виду тот же ApplicationController
, который он уже загрузил, так что фактически ProjectsController
наследуется от ApplicationController
хост-приложения, а не от движка. Поскольку метод translations_include_tag
не определен в ApplicationController
хост-приложения, ruby вызывает NoMethodError
, когда представление пытается его вызвать.
Решение
Я смог решить проблему, явно унаследовав от MyEngine
ApplicationController
:
в 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
После исправления проблемы с наследованием NoMethodError
исчезло.
В принятом ответе говорится, что нужно использовать нетерпеливую загрузку, что также решит проблему, поскольку заставляет движок ApplicationController
загружаться первым. Поскольку пространство имен ApplicationController
движка находится внутри MyEngine
, его полное имя — MyEngine::ApplicationController, что не конфликтует с ApplicationController
основного приложения, поскольку имена констант отличаются.
person
Cameron
schedule
11.02.2019