И аз се натъкнах на този проблем. Бях дефинирал ApplicationController
в моя двигател и виждах NoMethodError
s, когато се опитах да използвам помощни методи в един от контролерите на моя двигател.
Проблемът
Кодът изглеждаше нещо подобно:
в 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
Ако отида до маршрут в приложението за хост релси, след което щракна върху връзка, която води до 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
, когато изгледът се опитва да го извика.
Решението
Успях да коригирам проблема, като изрично наследих от ApplicationController
на MyEngine
:
в 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