Redmineプラグインを作るなら読むべき本家チュートリアルの日本語訳

Screen shot 2011-05-08 at 7.56.50 PM

Redmineのプラグインを作りながらRailsのテスト方法を学ぼうと思ったら、プラグインの作り方すら完全に忘れていたので、備忘録としてredmine.orgのPlugin Tutorialを訳してみる。これを読めばRedmineプラグイン作成が簡単にできるはず。

注意:チュートリアルを活用するにはRedmineのr1786以上が必要とのこと。

プラグインを作成する

プラグインを作るときは、様々なコマンドを利用する必要があるので、パスを通しておくとよい。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile1.txt

Redmineのプラグインはプラグインジェネレータがあるので、ジェネレータを使って雛形を作成する。コマンドの構文は以下。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile2.txt

実行するとプラグインの基盤となるファイルが自動生成される。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile3.txt

基本的には作成されたファイルをいじるだけでプラグインは作成可能。
次に、プラグインの説明ファイルであるinit.rbを編集する。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile36.txt

以下のように編集。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile4.txt

init.rbはメニューや権限設定でも修正するが、それは後ほど。
ここまできたら、Redmineを再起動してhttp://localhost:3000/admin/pluginsにアクセスすれば、プラグインリストに表示されているはず。

Screen shot 2011-05-08 at 6.38.47 PM

モデルの生成

サンプルとしてsawayakaというテーブルを作ってデータをうごうごできるようにする。モデル作成もコマンドで自動実行可能。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile5.txt

今回は、以下のように作ってみる。モデル名とプラグイン名が同じだとわかりにくい部分があるので、この例ではできるだけ異なる名前にしている。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile6.txt

モデル関係のファイルとmigrateファイルができあがる。

注意:migrationファイルが「タイムスタンプ_create_sawayakas.rb」などになっていたら「001」「002」といった具合にリネームする必要がある。タイムスタンプマイグレーションサポートができていない場合があるそうだ。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile7.txt

schema_migrations(plugin_schema_infoとあるけどそんなテーブルなかった)にタイムスタンプ情報ですでにテーブル情報を作っていた場合は、新しく付けた名前にアップデートする必要がある。MySQLの場合は以下で確認できる。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile8.txt

はじめは存在しないはず。migrate後は以下のようになる。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile9.txt

次に、migrateコマンドを実行し、データベースにテーブルを作成する。テーブル名は「モデル名 + s」になるので、この例のようないけてない名前にならないようにすること。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile10.txt

プラグインはそれぞれのmigration情報をそれぞれのdb/migrateフォルダ内に持っている。

作成したテーブルとモデルのテストとしてコンソールからデータ投入してみる。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile11.txt

うまく動いた。作成したモデルにメソッドを追加してみる。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile12.txt

以下のように修正。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile13.txt

コントローラを作る

DB操作ができるようになったので、次にコントローラを作成する。コントローラも以下のコマンドで自動作成可能。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile14.txt

今回は、coolコントローラとindexアクション、voteアクションを作ってみる。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile15.txt

コントローラを作ると、あわせてビューも作成される。そして、コントローラを修正する。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile37.txt

以下のように作成したモデルを使ってロジックを書き込む。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile16.txt

ビューも修正。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile17.txt

index.erbはindexアクションが呼ばれたときに表示されるように以下のように実装する。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile18.txt

コントローラのindexアクションで設定した@sawayakasをくるくる回してビューに表示しているだけ。今回は、index.erbで全て処理をしているのでvote.erbは必要ない。

ここまできたら、Redmineを再起動してプラグインの動作確認をしてみる。コントローラ名を指定してhttp://localhost:3000/coolにアクセスすると確認できるはず。

久しぶりにプラグインを作って気がついたのだけれど、コントローラやモデルは修正すると毎回Redmineを再起動する必要があった。ビューはいじりながら動作確認できたんだけど、最近はできなくなったのかな?(もしくは設定が必要?)

redmine.orgのPlugin Tutorialを訳してみる。

ここでは、プラグイン基盤、モデル、コントローラ、ビューの作成を説明。

注意:チュートリアルを活用するにはRedmineのr1786以上が必要とのこと。

翻訳

Redmineのバージョンによって翻訳ファイルの置き場所が変わってくる。

  • Redmine 0.9より前は「プラグインフォルダ/lang」
  • Redmine 0.9以上は「プラグインフォルダ/config/locales」

両方のバージョンでプラグインを動かしたい場合は、両方のフォルダに同じファイルを置く必要がある。
翻訳ファイルは以下のように記述する。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile19.txt

日本語は以下のように。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile20.txt

メニューの拡張

コントローラを実装しただけでは、プラグインを表示するため、URLにコントローラ名を入力する必要がある。これは不便。しかし、RedmineのプラグインAPIを利用すれば、標準のメニューにプラグインを表示することができる。まずはアプリケーションメニューに表示してみる。

書式は以下で、init.rbの一番下部分に記載する。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile21.txt

メニューには以下の5種類があり、menu_nameに指定できる。

  • :top_menu -トップ左のメニュー
  • :account_menu – ログイン/ログアウト部分の右に表示するメニュー
  • :application_menu – プロジェクトを選択していないときに表示されるメインメニュー
  • :project_menu – プロジェクトを選択したときに表示されるメインメニュー
  • :admin_menu – 管理画面で表示されるメインメニュー。「設定」と「プラグイン」の間に入る

item_nameにはプラグイン名を指定する(多分)。

有効なオプションは以下。

  • :param – プロジェクトIDとなるIDパラメタを指定する。デフォルトではidとなる。(例. :param => :project_id)
  • :if – アイテム表示前に呼ばれる。条件にtrueの場合のみアイテムは表示される
  • :caption – メニューで表示したい文字。以下の指定が可能
    • ローカライズ文字列のシンボル
    • 文字列
    • プロジェクトが引数として使えるProc
  • :before, :after – 対象のメニューの前や後ろにメニューを入れたい時にこれを使う(例. :after => :activity)
  • :first, :last – trueに設定した場合、メニューの最初や最後に表示できる (例. :last => true)
  • :html – a hash of html options that are passed to link_to when rendering the menu item

トップメニュー

${PLUGIN_ROOT/init.rbに以下のように記述する。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile22.txt

以下のように表示される。

Screen shot 2011-05-09 at 11.57.03 PM

アカウントメニュー

${PLUGIN_ROOT}/init.rbに以下を記述する。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile23.txt

以下のように表示される。

Screen shot 2011-05-10 at 12.01.23 AM

アプリケーションメニュー

${PLUGIN_ROOT}/init.rbに以下を記述する。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile24.txt

以下のようにメニュー表示される。このメニューはログインしていなくても見えてしまう。

Screen shot 2011-05-08 at 9.08.47 PM

プロジェクトメニュー

プロジェクトを開いたときのメニューに表示する。init.rbに以下に書くだけで良い。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile25.txt

この場合、パラメタproject_idが指定されるメニューリンクが、活動タブの後ろに配置される。メニューのリンクは「http://localhost:3000/cool?project_id=プロジェクトID」のようになる。
permissionの行では、プラグインのアクション(この場合、indexアクション、voteアクション)を公開(public => true)している。Redmineを再起動すると以下のように表示されるはず。

Screen shot 2011-05-09 at 11.33.02 PM

しかし、プロジェクトメニューの場合はこれだけではだめ。試しにクリックすると以下のように表示されるはず。

Screen shot 2011-05-09 at 11.45.42 PM

プロジェクトにあるその他のメニューが表示されない。これを何とかするために、コントローラ内で@projectにプロジェクトを設定する必要がある。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile26.txt

これを実装するために「param => :project_id」のような記述が必要になってくる。この実装を入れるとメニュークリック時に以下のようになる。

Screen shot 2011-05-09 at 11.47.38 PM

管理メニュー

新しい権限を設定する

このままだと誰でも投票できてしまうため、権限を設定する必要がある。まずは2つ権限設定を追加してみる。一つは投票画面を表示する権限で、もうひとつは投票する権限とする。これらの権限をつけるために、まずはpublicとなっている権限を削除する(:public => true の行を削除)。

権限設定は、${PLUGIN_ROOT}/init.rbに以下のように記述する。ここではプロジェクトメニューで実装。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile27.txt

そして、Redmineをリスタートし、http://localhost:3000/roles/reportにアクセス。

Screen shot 2011-05-25 at 8.55.41 PM

権限レポート画面では、設定した二つの権限設定が可能になっているはず。もちろん、アクションをきちんと権限で制限するために、いくつかのコードをコントローラに追加する必要がある。

今回は、indexアクションに:authorizeフィルタを追加し、このフィルタを呼び出す前に、find_projectによって@projectインスタンスを設定している。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile28.txt

find_projectは、indexアクションが呼ばれる前に呼び出される。さらに、上の例だと、voteアクションを実行した後も「redirect_to :action => ‘index’」でindexアクションが呼ばれるため、その前にfind_projectされてしまう。voteアクション時はproject_idが設定されていないため、app/views/cool/index.html.erbのvoteアクションを呼び出す部分でproject_idを設定する必要がある。以下がその例。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile29.txt

リンクURLのパラメタに「project_id => @project.id」を設定しているのがポイント。そして、リダイレクト時に、飛んできた「project_id」をパラメタに再設定するため、コントローラには「redirect_to :action => ‘index’, :project_id => params[:project_id]」と書かなければならない。そうじゃないとindexアクションへのリダイレクト時に、リクエストスコープのパラメタproject_idが消えてしまうため、「Couldn’t find Project without an ID」と怒られてしまう。

この修正によって、voteアクションも同じように、権限設定で付与されたユーザのみが実行できるアクションになる。
もし、権限のシンボルをいろいろな言語で設定したい場合は、以下のようにテキストラベルを言語ファイル(上記「翻訳」セクションを参考のこと)に作り設定することで解決する。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile30.txt

この例ではen.ymlに上記を記述することになる。もちろん、その他の言語でもOK。見ての通りだが、上記シンボルの場合は、「view_sample」の頭に「permission_」を付与している。init.rbでは「:permission_view_sample」ではなく、以下のように記述すればよい。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile31.txt

このシンボル(:permission_view_sample)をinit.rbに記述して、再起動すれば言語の切り替えができるようになる。

プロジェクトモジュールを作る

今の状態だと、作ったプラグインは全てのプロジェクトに追加されてしまう。しかし、「いくつかのプロジェクトで使う」といった柔軟性がほしい場合もありえる。そういうときは、プロジェクトモジュールとしてプラグインを作ることができる。プロジェクトモジュールにすることによって、プロジェクトの設定画面にチェックボックスが登場し、「使いたいモジュール」だけ選択する形にできるようになる。

では、今回作ったプラグインをプロジェクトモジュールにしてみよう。以下のように、${PLUBIN_ROOT}/init.rbの権限設定の文をproject_moduleでくくる。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile32.txt

そして、Redmineを再起動し、プロジェクトの設定画面のモジュールタブを開けば、プロジェクトモジュールとして表示されるはず。

Screen shot 2011-05-28 at 2.40.26 PM

これで、プロジェクトレベルで利用・解除ができる。

ビューの改善

スタイルシートの追加

ビューにスタイルシートを追加する方法の説明。sample.cssを${PLUBIN_ROOT}/assets/stylesheetsディレクトリに作成する。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile33.txt

Redmineが起動したときに、RailsによってWebサーバで利用可能にするために、assetsフォルダは自動的にpublic/plugin_assets/redmine_sample/にコピーされる。このため、CSSを変更したときは、Redmineを再起動させる必要がある。

それから、Redmineによってページのヘッダ部分にCSSを読み込ませるために、以下の行を${PLUGIN_ROOT}/app/views/cool/index.html.erbの最後に追加する。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile34.txt

「:plugin => ‘redmine_sample’」オプションはtylesheet_link_tagを呼び出すときの必須項目になる。Javascriptの場合は、CSSwの場合と同じように「javascript_include_tag」を呼び出せばよい。

ページタイトルを設定する

html_titleヘルパーを使うことでHTMLにタイトルを設定することができる。

https://gist.github.com/daipresents/cd8c75cbe343487bfa7968ee231b6589.js?file=gistfile35.txt

プラグインのテストについてはまた別途。