0

我正在使用具有一个Project模型的外部框架(redmine) has_many 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

我想检测何时通过回调 on 附加/删除新模块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

我认为 abefore_destroy可以用于检测删除,但它不会。发生这种情况是因为enabled_modules.clear对 , 的调用Project.enabled_module_names=不会在模块上调用“销毁”。它只是将它们project_id设置为零。所以我想我应该使用after_updateor before_update

如果我使用after_update,我怎样才能得到“以前的” project_id

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

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

编辑:我刚刚发现我可以用'_was'(即self.project_was)获得旧值。但是,collection.clear似乎不会触发更新回调。还有其他解决方案吗?

编辑 2:更改标题

4

3 回答 3

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),因此您可能希望至少选择该版本。

于 2010-01-22T02:51:26.667 回答
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在此之后,我能够在我的修补程序上检测到已启用模块(通过)的删除。

于 2010-01-22T09:17:07.977 回答
0

关于:

如果我使用 after_update,如何获得“上一个”project_id

也许试试 project_id_was,它是由ActiveRecord::Dirty提供的

于 2010-01-20T15:31:35.717 回答