2010-01-20 23 views
0

我正在使用一個外部框架(redmine),它有一個Project模型has_many EnabledModulesRedmine插件 - 檢測模塊的啓用和禁用

項目可以具有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將用於檢測清除工作,但它不會。 發生這種情況的原因是調用Project.enabled_module_names=,不會調用模塊上的「銷燬」。它只是將它們的project_id設置爲零。所以我想我應該使用after_updatebefore_update

如果我使用after_update,我怎樣才能得到'前'project_id

如果我使用before_update,如何區分'剛更新'的模塊和project_id將被重置爲nil的模塊?

我應該在這裏採用完全不同的方法嗎?

編輯:我只是found out,我可以用'_was'(即self.project_was)得到舊值。但是,collection.clear似乎沒有觸發更新回調。其他解決方案?

編輯2:更改標題

回答

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 

我不得不在供應商/插件/ 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)。

0

關於:

如果我使用after_update,我怎樣才能 '上一個' PROJECT_ID

也許嘗試project_id_was,它是由ActiveRecord::Dirty

提供
+0

嗨szelmek,感謝您的快速反應,你告訴我關於ActiveRecord :: Dirty同時我正在尋找它。但是,collection.clear不會觸發after_update或before_update,所以我必須嘗試其他方法。 – kikito 2010-01-20 15:40:35

1

看起來修訂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),所以你可能會想拿起至少那個版本。

+0

嗨史蒂文,謝謝你的回答。你是對的。我最終在項目中重新實現了enabled_module_names =,因此調用了「destroy」回調。下面我將自己的解決方案。 – kikito 2010-01-22 09:00:12