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

发布于 2024-08-18 04:10:42 字数 1617 浏览 3 评论 0原文

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

我想通过 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=enabled_modules.clear 调用不会调用模块上的“destroy”。它只是将它们的 project_id 设置为 nil。所以我想我应该使用 after_updatebefore_update

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

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

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

编辑:我只是发现我可以通过“_was”获取旧值(即self.project_was)。但是,collection.clear似乎没有触发更新回调。还有其他解决方案吗?

编辑2:更改标题

I'm working with an external framework (redmine) which has one Project model that has_many EnabledModules.

Projects can have EnabledModules "attached" or "removed" via the module names, like this:

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

I'd like to detect when new modules are attached/removed via callbacks on EnabledModule, and not modify the "original source code" if possible.

I can detect "attachments" like this:

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

I thought that a before_destroy would work for detecting removals, but it will not.
This happens because the enabled_modules.clear call on Project.enabled_module_names=, doesn't invoke 'destroy' on the modules. It just sets their project_id to nil. So I figured I should use a after_update or before_update.

If I use after_update, how can I get the 'previous' project_id?

If I use before_update, how can I differentiate between modules that are 'just updated' and modules whose project_id is going to be reset to nil?

Should I use a totally different approach here?

EDIT: I just found out that I could get the old values with '_was' (i.e. self.project_was). However, collection.clear doesn't seem to trigger update callbacks. Any other solutions?

EDIT 2: Changed title

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

§普罗旺斯的薰衣草 2024-08-25 04:10:42

看来 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),因此您可能至少需要选择该版本。

It looks like revision 2473 onwards of Redmine should solve your problem. See the diffs here:
http://www.redmine.org/projects/redmine/repository/diff/trunk/app/models/project.rb?rev=2473&rev_to=2319

Basically the code has been modified such that removed modules are destroyed rather than deleted, the difference being that model callbacks are not fired for deletes.

There's another related fix in revision 3036 that seems important (see http://www.redmine.org/issues/4200) so you might want to pick up at least that version.

夜无邪 2024-08-25 04:10:42

我最终重新实现了项目的 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)。

I ended up reimplementing the enabled_module_names= method of projects, including a file in vendor/plugins/my_plugin/lib/my_plugin/patches/project_patch.rb and alias.

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

I had to include some code on my vendor/plugins/my_plugin/init.rb file, too:

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

After this, I was able to detect deletions on enabled modules (via before_delete) on my patcher.

樱娆 2024-08-25 04:10:42

关于:

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

也许可以尝试project_id_was,它由 ActiveRecord::脏

Regarding:

If I use after_update, how can I get the 'previous' project_id

Maybe try project_id_was, it's provided by ActiveRecord::Dirty

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文