0

Projecthas_many という 1 つのモデルを持つ外部フレームワーク (redmine) を使用しています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削除の検出にはa が機能すると思っていましたが、そうではありません。これは、 の呼び出しがモジュールで「destroy」をenabled_modules.clear呼び出さないために発生します。Project.enabled_module_names=それらproject_idをnilに設定するだけです。だから私はafter_updateorを使うべきだと考えましたbefore_update

を使用する場合after_update、「前の」を取得するにはどうすればよいproject_idですか?

を使用する場合before_update、「更新されたばかり」のモジュールと project_id が nil にリセットされるモジュールをどのように区別できますか?

ここでまったく別のアプローチを使用する必要がありますか?

編集: 「_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 に答える