为冲突的Redmine插件改进了hacky ruby​​的“ method_alias”修复程序吗?

使用redmine 3.x,两个插件-redmine subtask list accordionSubtask list inherited fields之间存在依赖冲突。尝试查看问题时,同时安装两者都会引发500个错误。

    actionView::Template::Error (undefined method `sla_has_grandson_issues?' for #<#<Class:0x000056319e27d668>:0x00007f237ad02588>):
    1: <% if sla_has_grandson_issues?(@issue) %>
    2:   <%= content_for :header_tags do
    3:     stylesheet_link_tag(sla_use_css,:plugin => "redmine_subtask_list_accordion") +
    4:     javascript_include_tag("subtask_list_accordion" + (subtask_tree_client_processing? ? "_client" : ""),:plugin => "redmine_subtask_list_accordion")
  plugins/redmine_subtask_list_accordion/app/views/issues/_subtask_list_accordion_partial.html.erb:1:in `_292e8187f64bee60c61b7b15c99630ab'

经过反复试验,我们通过将以下内容添加到第一个插件的原始源代码中来解决此问题:

  included do
    alias_method :render_descendants_tree_original,:render_descendants_tree
    alias_method :render_descendants_tree,:switch_render_descendants_tree
    alias_method :sla_use_css,:sla_use_css
    alias_method :switch_render_descendants_tree,:switch_render_descendants_tree
    alias_method :render_descendants_tree_accordion,:render_descendants_tree_accordion
    alias_method :expand_tree_at_first?,:expand_tree_at_first?
    alias_method :sla_has_grandson_issues?,:sla_has_grandson_issues?
    alias_method :subtask_tree_client_processing?,:subtask_tree_client_processing?
    alias_method :subtask_list_accordion_tree_render_32?,:subtask_list_accordion_tree_render_32?
    alias_method :subtask_list_accordion_tree_render_33?,:subtask_list_accordion_tree_render_33?
    alias_method :subtask_list_accordion_tree_render_34?,:subtask_list_accordion_tree_render_34?

这是原始代码:

https://github.com/GEROMAX/redmine_subtask_list_accordion/blob/master/lib/redmine_subtask_list_accordion/patches/issues_helper_patch.rb

具有上述源代码中的前两个 alias_method 调用。

通过为原始类中的每个方法创建一个具有相同名称的别名方法,代码可以正常工作。但是,这似乎是一个错误修复程序,我不明白为什么有效。有人可以解释该修复程序为何起作用以及如何正确重写它吗?

kirecetycike 回答:为冲突的Redmine插件改进了hacky ruby​​的“ method_alias”修复程序吗?

alias_method在调用它的上下文中创建命名方法的副本

现在,如果原始方法(alias_method的第二个参数)在继承链的某个位置定义并在以后以任何方式进行了更改,那么您周围的副本仍然没有改变。也许可以解释您看到的行为。

关于重写:作为经验法则,丢弃所有方法别名(在两个插件中)并使用Module#prependThis SO Answer很好地概述了(猴子)修补Ruby代码的好坏技术。

在插件中修补Rails的视图助手似乎很棘手,这是由于Rails处理插件的方式(结果可能因代码加载顺序而异)。尽可能避免使用它或创建新的帮助程序模块,并使用类似的

命令将其添加到相关的控制器中
module RedmineSubtaskListAccordion
  module IssuesHelper
    def render_descendants_tree(issue)
      if sla_has_grandson_issues?(issue) &&  !subtask_tree_client_processing?
        render_descendants_tree_accordion(issue)
      else
        super # this will call the stock Redmine IssuesHelper#render_descendants_tree method
      end
    end
  end
end

# in init.rb:
IssuesController.class_eval do
  helper RedmineSubtaskListAccordion::IssuesHelper
end

前一段时间,我碰巧写了一个blog post关于这个确切的东西。希望可以在这里引用。

很显然,如果两个插件期望它们改变某种Redmine方法,使其表现出与现有Redmine相同的方式,仍然可能会发生冲突,但是根据我的经验,删除方法别名而不是尝试修补现有的助手将有助于避免很多问题。

更新:您链接到的特定模块中的其他大多数方法实际上并不属于该方法,但是例如可以混入Issue模型中(例如sla_has_grandson_issues?或声明为顶层插件名称空间(所有设置和Redmine版本相关的内容-例如RedmineSubtaskListAccordion.tree_render_34?)。

本文链接:https://www.f2er.com/3032797.html

大家都在问