Redmine插件 - 检测模块的启用和禁用

时间:2010-01-20 15:27:37

标签: ruby-on-rails collections callback clear redmine

我正在使用一个外部框架(redmine),它有一个Project模型,其中包含EnabledModules

项目可以通过模块名称“附加”或“删除”EnabledModules,如下所示:

class Project < ActiveRecord::Base
  ...
  has_many :enabled_modules, :dependent => :delete_all
  ...
  def enabled_module_names=(module_names)
    enabled_modules.clear
    module_names = [] unless module_names && module_names.is_a?(Array)
    module_names.each do |name|
      enabled_modules << EnabledModule.new(:name => name.to_s)
    end
  end
end

我想通过EnabledModule上的回调来检测何时附加/删除新模块,如果可能的话,不要修改“原始源代码”。

我可以像这样检测“附件”:

class EnabledModule < ActiveRecord::Base
  belongs_to :project

  after_create :module_created

  def module_created
    logger.log("Module attached to project #{self.project_id}")
  end
end

我认为before_destroy可用于检测删除,但它不会。 发生这种情况是因为对enabled_modules.clear的{​​{1}}调用不会在模块上调用'destroy'。它只是将Project.enabled_module_names=设置为零。所以我想我应该使用project_idafter_update

如果我使用before_update,我怎样才能获得'上一个'after_update

如果我使用project_id,我如何区分“刚更新”的模块和project_id将重置为nil的模块?

我应该在这里使用完全不同的方法吗?

编辑:我只是found out我可以使用'_was'(即before_update)获取旧值。但是,self.project_was似乎没有触发更新回调。还有其他解决方案吗?

编辑2:更改了标题

3 个答案:

答案 0 :(得分:1)

看起来Redmine的2473版本应该可以解决您的问题。在这里看到差异: http://www.redmine.org/projects/redmine/repository/diff/trunk/app/models/project.rb?rev=2473&rev_to=2319

基本上代码已被修改,以便删除而不是删除已删除的模块,不同之处在于不会为删除触发模型回调。

修订版3036中的另一个相关修复程序似乎很重要(请参阅http://www.redmine.org/issues/4200),因此您可能希望至少选择该版本。

答案 1 :(得分:1)

我最终重新实现了项目的enabled_module_names=方法,包括vendor / plugins / my_plugin / lib / my_plugin / patches / project_patch.rb和别名中的文件。

module MyPlugin
  module Patches
    module ProjectPatch
      def self.included(base)
        base.send(:include, InstanceMethods)
        base.extend(ClassMethods)
        base.class_eval do
          unloadable # Send unloadable so it will not be unloaded in development

          # This replaces the existing version of enabled_module_names with a new one
          # It is needed because we need the "destroy" callbacks to be fired,
          # and only on the erased modules (not all of them - the default 
          # implementation starts by wiping them out in v0.8'ish)
          alias_method :enabled_module_names=, :sympa_enabled_module_names=
        end
      end

      module ClassMethods
      end

      module InstanceMethods

        # Redefine enabled_module_names so it invokes 
        # mod.destroy on disconnected modules
        def sympa_enabled_module_names=(module_names)

          module_names = [] unless module_names and module_names.is_a?(Array)
          module_names = module_names.collect(&:to_s)
          # remove disabled modules
          enabled_modules.each {|mod| mod.destroy unless module_names.include?(mod.name)}

          # detect the modules that are new, and create those only
          module_names.reject {|name| module_enabled?(name)}.each {|name| enabled_modules << EnabledModule.new(:name => name) }
        end
      end
    end
  end
end

我必须在我的vendor / plugins / my_plugin / init.rb文件中包含一些代码:

require 'redmine'

require 'dispatcher'

# you can add additional lines here for patching users, memberships, etc...
Dispatcher.to_prepare :redmine_sympa do
  require_dependency 'project'
  require_dependency 'enabled_module'

  Project.send(:include, RedmineSympa::Patches::ProjectPatch)
  EnabledModule.send(:include, RedmineSympa::Patches::EnabledModulePatch)

end

Redmine::Plugin.register :redmine_sympa do
# ... usual redmine plugin init stuff
end

在此之后,我能够在我的修补程序上检测已启用模块的删除(通过before_delete)。

答案 2 :(得分:0)

关于:

  

如果我使用after_update,我怎样才能获得'previous'project_id

也许尝试project_id_was,它由ActiveRecord::Dirty

提供