[英]Improving on hacky ruby 'method_alias' fix for conflicting redmine plugins?
使用 redmine 3.x,我有兩個插件之間的依賴沖突 - redmine 子任務列表手風琴和 子任務列表繼承字段。 嘗試查看問題時,同時安裝兩者會引發 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
在調用它的上下文中創建命名方法的副本。
現在,如果原始方法( alias_method
第二個參數)定義在繼承鏈的某個位置並在以后以任何方式進行了更改,那么您仍然擁有未更改的副本。 這可能解釋了您看到的行為。
至於重寫:根據經驗,丟棄所有方法別名(在兩個插件中)並使用Module#prepend
。 這個 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
不久前我碰巧寫了一篇關於這件事的博客文章。 希望可以在這里參考。
顯然,如果兩個插件期望某個 Redmine 方法按照它在股票 Redmine 中的行為方式進行更改,則可能仍然存在沖突,但是根據我的經驗,刪除方法別名而不是試圖修補已經存在的幫助程序有助於避免許多問題。
更新:您鏈接到的特定模塊中的大多數其他方法實際上不屬於那里,但例如可以混合到Issue
模型中(如sla_has_grandson_issues?
或聲明為頂級插件命名空間中的方法(所有設置和 Redmine版本相關的東西 - 例如RedmineSubtaskListAccordion.tree_render_34?
)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.