使用redmine 3.x,两个插件-redmine subtask list accordion和Subtask 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?
这是原始代码:
哪个具有上述源代码中的前两个alias_method调用。
通过为原始类中的每个方法制作一个具有相同名称的别名方法,代码可以正常工作。但是,这似乎是一个错误修复程序,我不理解为什么可以工作。有人可以解释该修复程序为何起作用以及如何正确重写?
alias_method
”在调用该方法的上下文中创建该方法的copy。
现在,如果原始方法(alias_method
的第二个参数)在继承链的某个位置定义并在以后以任何方式进行了更改,那么您仍然拥有该副本的副本,并且该副本没有改变。可能可以解释您看到的行为。
关于重写:根据经验,丢弃所有方法别名(在两个插件中)并使用Module#prepend
。 This 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?
。