从插件包含控制器的方法

Séb*_*oon 5 ruby plugins ruby-on-rails redmine

使用Rails的2.3.11,我创建管理平台是一个插件添加方法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
Run Code Online (Sandbox Code Playgroud)

现在,如果我将此模块直接包含在application_controller.rb文件中,如下所示:

class ApplicationController < ActionController::Base
  include ApplicationControllerPatch

  ...
end
Run Code Online (Sandbox Code Playgroud)

一切正常,但是我想通过从插件本身包含这个模块来避免编辑核心源代码.到目前为止,如果我这样做:

ApplicationController.send(:include, ApplicationControllerPatch)
Run Code Online (Sandbox Code Playgroud)

直接来自这个模块文件(位于插件文件夹中).这将为请求正确加载,然后由控制器覆盖(我猜).

完成此任务的方法是什么?

Hol*_*ust 4

一种常见的模式是在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
Run Code Online (Sandbox Code Playgroud)

您的补丁应始终位于以您的插件命名的模块内,以免遇到定义相同模块名称的多个插件的问题。然后把补丁放进去lib/my_plugin/application_controller_patch.rb。这样,Rails 自动加载器就会自动拾取它。

把这个放入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
Run Code Online (Sandbox Code Playgroud)