Включение методов в контроллер из плагина - PullRequest
5 голосов
/ 29 октября 2011

Используя Rails 2.3.11 , я создаю плагин для Redmine, который добавляет методы в ApplicationController.

Я создал следующий модуль, в плагине:

module ApplicationControllerPatch
  def self.included(base) # :nodoc:
    base.class_eval do
      rescue_from AnException, :with => :rescue_method

      def rescue_method(exception)
        ...
      end
    end
  end
end

Теперь, если я включу этот модуль непосредственно в файл application_controller.rb, например:

class ApplicationController < ActionController::Base
  include ApplicationControllerPatch

  ...
end

Все работает просто отлично, однако я хотел бы избегайте редактирования исходного кода, включив этот модуль из самого плагина.Пока, если я сделаю:

ApplicationController.send(:include, ApplicationControllerPatch)

непосредственно из этого файла модуля (находится в папке плагина).Это будет правильно загружено для запроса и затем будет перезаписано контроллером (я думаю).

Как это сделать?

Ответы [ 2 ]

4 голосов
/ 29 октября 2011

Обычным примером является использование Dispatcher.to_prepare внутри init.rb вашего плагина. Это необходимо, потому что в режиме разработки (или, как правило, если config.cache_classes = false) Rails перезагружает все классы непосредственно перед каждым запросом для получения изменений без необходимости каждый раз полностью перезагружать сервер приложений.

Это, однако, означает, что вы должны применить свой патч снова после перезагрузки класса, так как Rails не может знать, какие модули были внедрены позже. Используя Dispatcher.to_prepare, вы можете достичь именно этого. Код, определенный в блоке, выполняется один раз в производственном режиме и перед каждым запросом в режиме разработки, что делает его главным местом для базовых классов обезьяньего патча.

Преимуществом этого подхода является то, что вы можете иметь свои плагины автономными и не нужно ничего менять в окружающем приложении.

Поместите это в свой init.rb, например. vendor/plugins/my_plugin/init.rb

require 'redmine'

# Patches to the Redmine core.
require 'dispatcher'

Dispatcher.to_prepare do
  ApplicationController.send(:include, MyPlugin::ApplicationControllerPatch) unless ApplicationController.include?(RedmineSpentTimeColumn::Patches::IssuePatch)
end

Redmine::Plugin.register :my_plugin do
  name 'My Plugin'
  [...]
end

Ваш патч должен всегда находиться в пространстве имен внутри модуля, названного в честь вашего плагина, чтобы не было проблем с несколькими плагинами, определяющими одинаковые имена модулей. Затем поместите патч в lib/my_plugin/application_controller_patch.rb. Таким образом, он будет автоматически загружен Rails Autoloader.

Поместите это в vendor/plugins/my_plugin/lib/my_plugin/application_controller_patch.rb

module MyPlugin
  module ApplicationControllerPatch
    def self.included(base) # :nodoc:
      base.class_eval do
        rescue_from AnException, :with => :rescue_method

        def rescue_method(exception)
          [...]
        end
      end
    end
  end
end
0 голосов
/ 29 октября 2011

Такая проблема возникает только в dev, потому что классы перезагружаются, но не гемы.

Итак, добавьте ваш метод send в блок config.to_prepare в config / environment / development.rb

Для получения дополнительной информации прочтите документацию Rails относительно процесса инициализации.

...