Вспомогательные методы монтируемых на Rails двигателей не найдены при маршрутизации из основного приложения

У меня есть модуль в виде монтируемого движка, подключенного к основному приложению через

mount MyEngine::Engine, :at => '/myengine'

У меня все пространство имен находится в negine, а у движка есть свои представления в engine/app/views/myengine/

Все работает нормально, когда я запускаю сервер rails, а затем пытаюсь получить доступ

локальный: 3000/myengine

сначала перейдите в корень основного приложения и вернитесь к движку по ссылке в индексном представлении основного приложения.

Однако, когда я запускаю сервер, иду на localhost: 3000 и оттуда щелкаю ссылку на модуль движка, он пытается правильно получить представления, однако методы, содержащиеся в помощниках движка, вызывают ошибку при вызове для них быть неопределенными.

я на рельсах 4


person Ahmadposten    schedule 23.06.2015    source источник


Ответы (3)


Я использовал нетерпеливый_load для загрузки монтируемого движка, который был инициализирован в основном приложении, и теперь все работает.

Myengine::Engine.eager_load!

person Ahmadposten    schedule 13.08.2015

Я тоже только что столкнулся с этой проблемой. Я определил 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

Вам необходимо явно включить помощников в файл lib/engine.rb:

initializer 'your-gem-name.setup_helpers' do |app|
    app.config.to_prepare do
      ActionController::Base.send :include, HelperModuleName
    end
  end
end
person Yury Lebedev    schedule 23.06.2015
comment
Та же проблема, я также хотел бы подчеркнуть, что проблема возникает только тогда, когда я пытаюсь получить доступ к модулю после первого доступа к основному приложению, однако, когда я сначала получаю доступ к модулю, после этого все кажется нормальным, и я могу правильно перемещаться. - person Ahmadposten; 23.06.2015
comment
есть ли шанс, что в вашем приложении есть модуль с таким же названием? - person Yury Lebedev; 23.06.2015
comment
нет другого модуля с таким же или близким к нему названием - person Ahmadposten; 23.06.2015