昨日(Redmineプラグイン作成でHookを使ってみる - torutkのブログ)は、Redmineが用意したフックの機構を使って、チケット一覧表示画面の下に任意の表示を差し込んでみました。ただし、表示は固定文字列のみでした。Ruby on Railsでは、拡張子.erbのファイルでHTMLのテンプレートを用意し実行時に決まる値を反映することなどが可能です。昨日は固定文字列だけ書いて、動的な記述を課題として積み残していたerbファイルの記述方法を少し追ってみます。
プラグインのapp/views/issues/_issuesIndexBottom.html.erb をいじる
Redmine本体には、拡張子が.html.erbとなっている多数のファイルが存在します。これらを参考とします。
チケット一覧表示では、
このindex.html.erbを見ていると、@で始まる変数の参照がいくつか見られます。
@project @query @issues @issue_pages @issue_count @sort_criteria
Ruby on Railsでは、HTMLのテンプレートファイル名は、<アクション名>.html.erbとする規約のようです。Redmineのチケット一覧表示はアクションがindexなので、index.html.erbとなっていると思われます。テンプレートはふつうにHTMLの記述が可能ですが、実行時に決まる動的な値は、アクション(コントローラ)のインスタンス変数に値を詰め、テンプレートからインスタンス変数を参照して値を適用します。そのインスタンス変数が上述の@で始まる変数です。
そこで、どんなインスタンス変数が存在するのかを確認するため、
class IssuesController < ApplicationController :(略) def index : @issue_count = @query.issue_count @issue_pages = Paginator.new @issue_count, @limit, params['page'] @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version], .. @issue_count_by_group = @query.issue_count_by_group
といったインスタンス変数が定義されています。
Rubyでは、変数宣言はなく、先頭が「@」で始まる変数をインスタンス変数として扱います。
では、昨日作成したView hooksとして差し込むテンプレートを少し修正してみます。
- プラグインのapp/views/issues/_issuesIndexBottom.html.erb
<h3>HOOKED</h3> <p>issue count is <%= @issue_count %></p>
修正を保存し、チケット一覧表示ページにアクセスします。development モードだからか、WEBrickの再起動をしなくても反映されました。
すると
HOOKED issue count is 26
と表示されました。
値ではなく、オブジェクトへのメソッド呼び出しの結果を表示したい場合も、
<h3>HOOKED</h3> <p>issues displayed are <%= @issues.length %></p>
とメソッド呼び出しの記述が可能です。(lengthは、配列の要素数。ちなみにこの@issues.lengthは表示している件数が返りました)
フック(View hooks)とは
Redmine本体であらかじめ拡張用に用意された表示部位がView hooksで、チケット一覧表示の場合は、一覧表示の下にview_issues_index_bottomの名前でフックが設けられています。
フックにコールバックをしかけておくと、表示に際してコールバックが呼ばれ、そこに追加の表示を入れ込むことができます。コールバックは、Redmine::Hook::ViewListenerクラスを継承したクラスとして定義し、init.rbにrequire_dependency文で定義を読み込ませます。
コールバックの処理は、表示系の場合 render_on ヘルパーでフック名と表示テンプレート(パーシャル?)を指定しておくと、そのテンプレートによって生成された表示がフックの部位に差し込まれます。
表示テンプレートで参照できるのは、コントローラのインスタンス変数となるので、コントローラが想定している範囲のデータを使って動的な表示が実現できます。逆に、それ以上のことをやりたいとしたら、フックではなく別の手段を使うことになるのかと思います。
おまけ
コントローラフック
チケット表示関係のコントローラフックを探してみると(grep -r call_hook * | grep control)、次の名前が関係していそうです。
- :controller_issues_new_before_save
- :controller_issues_new_after_save
- :controller_issues_bulk_edit_before_save
- :controller_issues_edit_before_save
- :controller_issues_edit_after_save
チケット変更の前後で処理を差し込むことができそうです。
ただ、ここには一覧表示に差し込むフックはないようです。
モデルフック
Redmine全体で2つのようです。
- model_changeset_scan_commit_for_issue_ids_pre_issue_update
- model_project_copy_before_save