外掛內部¶
本頁面將用於集中存放有關 Redmine 外掛開發的資訊。
覆寫 Redmine 核心¶
您可以在 Redmine 中覆寫視圖,但不能覆寫控制器或模型。如果您嘗試覆寫一個虛構外掛「MyPlugin」的控制器(或模型)和視圖,以下是 Redmine/Rails 的運作方式:
控制器(或模型)¶
- Rails 啟動並載入其所有框架
- Rails 開始載入外掛中的程式碼
- Rails 在 MyPlugin 中找到「IssueController」,並看到它定義了一個「show」動作
- Rails 載入所有其他外掛
- Rails 然後從「../app」載入應用程式
- Rails 再次找到「IssueController」,並看到它也定義了一個「show」動作
- Rails(或者更確切地說是 Ruby)使用「../app」中的「show」動作覆寫外掛中的「show」動作
- Rails 完成載入並提供請求
視圖¶
視圖載入非常相似,但有一個小差別(因為 Redmine 對 Engines 的修補程式)
- Rails 啟動並載入其所有框架
- Rails 開始載入外掛中的程式碼
- Rails 在「../vendor/plugins/my_plugin/app/views」中找到一個視圖目錄,並將其「前置」到視圖路徑中
- Rails 載入所有其他外掛
- Rails 然後從「../app」載入應用程式
- Rails 完成載入並提供請求
- 請求進入,需要呈現視圖
- Rails 尋找匹配的範本,並載入外掛的範本,因為它被「前置」到視圖路徑中
- Rails 呈現外掛的視圖
由於使用 Ruby 的方式(透過包含模組)擴充模型和控制器非常容易,因此 Redmine 不應該(也不會)維護用於覆寫核心模型和/或控制器的 API。另一方面,視圖很棘手(因為 Rails 的魔力),因此用於覆寫它們的 API 更有用(因此在 Redmine 中實現)。
要覆寫現有的 Redmine 核心視圖,只需建立一個與「../app/views/」中的視圖檔案同名的檔案,Redmine 就會使用它。例如,要覆寫專案索引頁面,請將檔案新增到「../vendor/plugins/my_plugin/app/views/projects/index.html.erb」。
擴充 Redmine 核心¶
如上所述:您很少需要覆寫模型/控制器。相反,您應該- 向模型/控制器新增新方法,或
- 包裝現有方法。
新增方法¶
在 Eric Davis 的「預算外掛」中可以找到一個「新增方法」的快速範例。在這裡,他向 Issue 新增了一個名為「deliverable_subject」的新方法,並聲明了一個關係。
module IssuePatch
def self.included(base) # :nodoc:
base.send(:include, InstanceMethods)
end
module InstanceMethods
# Wraps the association to get the Deliverable subject. Needed for the
# Query and filtering
def deliverable_subject
unless self.deliverable.nil?
return self.deliverable.subject
end
end
end
end
包裝現有方法¶
注意!
alias_method_chain 模式在 Rails 5 中已棄用,因此此技術僅適用於 4.0.0 以下版本的 Redmine。
一個關於**封裝現有方法**的快速範例可以在 Eric Davis 的 Rate 插件 中找到。他在這裡使用 alias_method_chain
來掛鉤 UsersHelper 並封裝 user_settings_tabs
方法。因此,當 Redmine 核心呼叫 user_settings_tabs
時,程式碼路徑如下所示
- Redmine 核心呼叫
UsersHelper#user_settings_tabs
UsersHelper#user_settings_tabs
執行(實際上是UsersHelper#user_settings_tabs_with_rate_tab
)UsersHelper#user_settings_tabs_with_rate_tab
呼叫原始的UsersHelper#user_settings_tabs
(已重新命名為UsersHelper#user_settings_tabs_without_rate_tab
)- 然後將一個新的雜湊新增到結果中
UsersHelper#user_settings_tabs_with_rate_tab
將組合後的結果返回給 Redmine 核心,然後進行渲染
module RateUsersHelperPatch
def self.included(base) # :nodoc:
base.send(:include, InstanceMethods)
base.class_eval do
alias_method_chain :user_settings_tabs, :rate_tab
end
end
module InstanceMethods
# Adds a rates tab to the user administration page
def user_settings_tabs_with_rate_tab
tabs = user_settings_tabs_without_rate_tab
tabs << { :name => 'rates', :partial => 'users/rates', :label => :rate_label_rate_history}
return tabs
end
end
end
請務必注意,這種封裝每個方法只能執行一次。在多個插件使用此技巧的情況下,只有最後一次評估 alias_method_chain
才會有效,而之前的所有評估都將被忽略。
alias_method_chain
是一個相當進階的方法,但它也非常強大。
在 Redmine 插件中使用 Rails 回調¶
例如,當您想要掛鉤到所有已儲存/建立的問題時,最好使用 Rails 回調,而不是 Redmine 掛鉤。主要原因是當建立新問題時,不會觸發:controller_issues_edit_before_save
掛鉤。例如,請參閱 Eric Davis 的「看板插件」中的實現
- http://github.com/edavis10/redmine_kanban/blob/000cf175795c18033caa43082c4e4d0a9f989623/init.rb#L10
- http://github.com/edavis10/redmine_kanban/blob/000cf175795c18033caa43082c4e4d0a9f989623/lib/redmine_kanban/issue_patch.rb#L13
這將確保每次儲存問題(新增或更新)時都會執行 issue.update_kanban_from_issue
。
如果您只想掛鉤到新問題,則可以使用 before_create
回調而不是 after_save
回調。如果您想確保在執行程式碼之前確實已成功儲存問題,則最好使用 after_create
回調。
掛鉤到我的頁面¶
常見問題¶
- 為什麼我的區塊的下拉式選單沒有本地化?根據慣例,下拉式方塊中條目的名稱是由插件的語言環境檔案中的條目組成。此條目的名稱必須與「我的網站」區塊檔案名稱相同,例如 redmine/vendor/plugins/<myplugin_folder>/app/views/my/blocks/<myblocks_view_file_name>.erb。因此,您需要在語言環境中新增一行「<myblocks_view_file_name>: <在此處放置我的區塊配置中下拉式項目的翻譯>」,例如 redmine/vendor/plugins/<myplugin_folder>/config/locale/zh-TW.yml。
如果語言環境檔案中沒有定義此字串,則一律會使用沒有副檔名的檔案名稱 <myblocks_view_file_name> 作為下拉式選單中的標籤。