www.redmine.orgのPlugin Turorial を和訳してみます。
プラグイン チュートリアル¶
注意: このチュートリアルはRedmineの開発リビジョン r1786 以上を対象にしています。
- Table of contents
- プラグイン チュートリアル
新しいプラグインを作る。¶
プラグインの新規作成はRedmineのプラグインジェネレータを使用して行うことができます。
ジェネレータのコマンドは以下です。:
ruby script/generate redmine_plugin <plugin_name>
コマンドプロンプトを開き "cd" であなたがredmineをインストールしたディレクトリに移動し、以下のコマンドを実行してみましょう。:
% ruby script/generate redmine_plugin Polls
vendor/plugins/redmine_polls の下に以下のようなファイルとディレクトリが作られます:
create vendor/plugins/redmine_polls/app/controllers
create vendor/plugins/redmine_polls/app/helpers
create vendor/plugins/redmine_polls/app/models
create vendor/plugins/redmine_polls/app/views
create vendor/plugins/redmine_polls/db/migrate
create vendor/plugins/redmine_polls/lib/tasks
create vendor/plugins/redmine_polls/assets/images
create vendor/plugins/redmine_polls/assets/javascripts
create vendor/plugins/redmine_polls/assets/stylesheets
create vendor/plugins/redmine_polls/lang
create vendor/plugins/redmine_polls/README
create vendor/plugins/redmine_polls/init.rb
create vendor/plugins/redmine_polls/lang/en.yml
vendor/plugins/redmine_polls/init.rb を編集してあなたのプラグインの情報を書き込んでください。(name, author, description および version):
require 'redmine'
Redmine::Plugin.register :redmine_polls do
name 'Polls plugin'
author 'John Smith'
description 'A plugin for managing polls'
version '0.0.1'
end
そしてRedmineを起動し、ブラウザから次のアドレスを入力します。http://localhost:3000/admin/info.
ログイン後、あなたのプラグインがプラグイン一覧に加わっていることが確認できます。

モデルを作る¶
それではこのプラグインのモデルとして Poll を作ってみましょう。:
ruby script/generate redmine_plugin_model polls poll question:string yes:integer no:integer
このコマンドで Poll モデルおよびPollモデルに対応したマイグレーションファイルが作成されます。
(訳注:マイグレーションファイルとは、RedmineのDBにこのモデル用のテーブルを作成するためのスクリプトファイルです)
ここで注意が必要です。timestamped migrationは今のRedmineプラグインエンジンではサポートされていません。ファイル名についているタイムスタンプを"001", "002"のような名前に変更してください。
実際にデータベースへのマイグレーションを行うためには以下のコマンドを実行します。:
rake db:migrate_plugins
すべてのプラグインはそれぞれに自身のマイグレーションファイルを持っています。
それではconsoleスクリプトからPollのデータを追加してみましょう。ちゃんとテーブルが作られていることを確認できます。consoleを使用すると対話的にRedmineを動かして確認できます。また、遊びながらいろいろな情報を得ることができます。それでは2つのPollオブジェクトを作ります。
script/console >> Poll.create(:question => "Can you see this poll ?") >> Poll.create(:question => "And can you see this other poll ?") >> exit
プラグインディレクトリの vendor/plugins/redmine_polls/app/models/poll.rb を編集して #vote メソッドを追加しましょう。このメソッドはコントローラから実行されるものです。:
class Poll < ActiveRecord::Base
def vote(answer)
increment(answer == 'yes' ? :yes : :no)
end
end
コントローラを作成する。¶
この段階ではまだこのプラグインは何もすることができません。このプラグインにコントローラを追加してみましょう。コントローラの作成にはプラグインコントローラジェネレータを使用できます。文法は以下です。:
ruby script/generate redmine_plugin_controller <plugin_name> <controller_name> [<actions>]
ではコマンドプロンプトから以下のように打ってみましょう。:
% ruby script/generate redmine_plugin_controller Polls polls index vote
exists app/controllers/
exists app/helpers/
create app/views/polls
create test/functional/
create app/controllers/polls_controller.rb
create test/functional/polls_controller_test.rb
create app/helpers/polls_helper.rb
create app/views/polls/index.html.erb
create app/views/polls/vote.html.erb
コントローラ PollsController と2つのアクション (#index and #vote) が作成されます。
vendor/plugins/redmine_polls/app/controllers/polls_controller.rb を編集して 2つのアクションを実装します。
class PollsController < ApplicationController
unloadable
def index
@polls = Poll.find(:all)
end
def vote
poll = Poll.find(params[:id])
poll.vote(params[:answer])
if poll.save
flash[:notice] = 'Vote saved.'
redirect_to :action => 'index'
end
end
end
そして vendor/plugins/redmine_polls/app/views/polls/index.html.erb を編集すると先ほど作成した2つのpollを表示できます。:
<h2>Polls</h2>
<% @polls.each do |poll| %>
<p>
<%= poll[:question] %>?
<%= link_to 'Yes', {:action => 'vote', :id => poll[:id], :answer => 'yes'}, :method => :post %> (<%= poll[:yes] %>) /
<%= link_to 'No', {:action => 'vote', :id => poll[:id], :answer => 'no'}, :method => :post %> (<%= poll[:no] %>)
</p>
<% end %>
vendor/plugins/redmine_polls/app/views/polls/vote.html.erb は対応するactionから使われることがないので削除してよいです。
さあ、Redmineを再起動してブラウザから http://localhost:3000/polls にアクセスしましょう。
2つのpollが確認でき、それらに投票することができるでしょう。:

もしRedmineをプロダクションモードで動かしていない場合、pollの結果はリクエスト毎にリセットされます。これは今回の例ではpollモデルをclass変数に格納しているためです。
メニューを拡張する。¶
コントローラは動くようになりましたが、このままではユーザはURLを知らない限り投票画面を見ることができません。RedmineのプラグインAPIを使用するとメニューを拡張できます。アプリケーションメニューに新しい項目を追加してみましょう。
アプリケーションメニューを拡張する。¶
vendor/plugins/redmine_polls/init.rb を編集してplugin registration blockの最後に以下の行を追加してください。:
Redmine::Plugin.register :redmine_polls do
[...]
menu :application_menu, :polls, { :controller => 'polls', :action => 'index' }, :caption => 'Polls'
end
文法は以下です。:
menu(menu_name, item_name, url, options={})
拡張できるメニューは4種類です。:
:top_menu- 最上部の左側のメニュー。:account_menu- 最上部の右側のメニュー。ログイン/ログアウトがある。:application_menu- プロジェクトの外でのメインメニュー。:project_menu- プロジェクト内でのメインメニュー。
以下のオプションが使えます。:
:param- プロジェクトIDを渡すのに用いられる変数のキー。 (デフォルトは:id):if- メニュー項目のレンダリング前に呼ばれるProc。メニュー項目はこのProcの戻りがtrueの場合にのみ表示される。:caption- メニューのキャプション。以下が使えます。:- ローカライズ文字列用シンボル
- 文字列
- projectを引数としたProc
:before,:after- メニューを挿入する場所の指定 (例:after => :activity訳注:「活動」ページの後ろに挿入される):last- trueに設定するとメニューの最後に追加される。 (例:last => true):html_options- html オプションのHash。メニュー表示時のlink_toに渡される。訳注:link_toはRailsのAPI
今回の例ではメニュー項目をアプリケーションメニューに追加します。アプリケーションメニューはデフォルトでは空です。
Redmineを再起動して http://localhost:3000 にアクセスしてみましょう。:

ようこそ画面のPollsタブをクリックして投票画面に行けるはずです。
プロジェクトメニューを拡張する。¶
さあ、今度はpollsをプロジェクト用プラグインとした場合の例です。(今回のpollモデルはそう設計されてませんが)。Pollsタブをプロジェクトメニューに追加しましょう。init.rb を開いて先ほど追加した行を以下の2行に書き換えてください。:
Redmine::Plugin.register :redmine_polls do
[...]
permission :polls, {:polls => [:index, :vote]}, :public => true
menu :project_menu, :polls, { :controller => 'polls', :action => 'index' }, :caption => 'Polls', :after => :activity, :param => :project_id
end
2行目がプロジェクトメニューにPollsタブを追加する定義です。活動タブのすぐ後ろに追加します。
最初の行は PollsController の2つのアクションをpulicにするための設定です。詳細については後ほど説明します。
Redmineを再起動し、プロジェクトを表示します。:

Pollsタブをクリックしてください。プロジェクトメニューが消えてしまうことに気付きましたか?
プロジェクトメニューを表示しておくためにはコントローラのインスタンス変数 @project を設定してあげる必要があります。
PollsController を以下のように編集します。:
def index
@project = Project.find(params[:project_id])
@polls = Poll.find(:all) # @project.polls
end
プロジェクトIDはparamの中の :project_id に格納されています。なぜなら先ほどのメニューの定義で :param => :project_id と設定したからです。
さあ、これでPollsタブをクリックしてもプロジェクトメニューが消えなくなりました。:

パーミッションを定義する。¶
この状態ではすべての人が投票を行うことができます。ではパーミッションの定義をしてみましょう。
ここでは2種類のプロジェクトベースのパーミッションを定義します。ひとつはpollsの表示に関するもの、もう一つは投票に関するものです。これを行うと、パーミッションはpublicでは無くなります。(:public => true オプションは削除します).
vendor/plugins/redmine_polls/init.rb を編集して先ほどのパーミッション定義を以下の2行に置き換えます。:
permission :view_polls, :polls => :index
permission :vote_polls, :polls => :vote
Redmineを再起動して次のURLにアクセスしてみましょう。 http://localhost:3000/roles/report:

これで既存のロールに対してパーミッションを設定できるようになりました。
もちろん、パーミッションに応じてユーザのアクセス制御を行うためにはPollsControllerにコードを追加する必要があります。
今回の場合は :authorize フィルターを追加すること、およびこのフィルターが呼ばれる前に必ず @project に値がセットされるようにするだけです。
#index アクションでは以下のようにします。:
class PollsController < ApplicationController
unloadable
before_filter :find_project, :authorize, :only => :index
[...]
def index
@polls = Poll.find(:all) # @project.polls
end
[...]
private
def find_project
# @project variable must be set before calling the authorize filter
@project = Project.find(params[:project_id])
end
end
#vote アクションが動く前に現在のプロジェクトを取得します。これを行うと、投票は管理者もしくはこのプロジェクトの許可されたロールのユーザ以外行えなくなります。
プロジェクトモジュールを作る。¶
今現在、pollの機能はすべてのプロジェクトに追加されています。しかし、pollsを限られたプロジェクトのみに使わせたい場合もあるでしょう。
ここでは 'Polls' プロジェクトモジュールを作成します. これはパーミッション定義を #project_module 定義で囲むことによって実現します。
init.rb を編集してパーミッションの定義を変更します。:
project_module :polls do
permission :view_polls, :polls => :index
permission :vote_polls, :polls => :vote
end
Redmineを再起動し、適当なプロジェクトの設定メニューを開きます。そしてモジュールタブをクリックします。するとモジュールリストの最後にPolls moduleがあることが確認できます。 (デフォルトではチェックはついていません):

これでプロジェクト毎にPollsの有効・無効を選択できるようになりました。
プラグインの表示を拡張する。¶
スタイルシートを追加する。¶
それではプラグインのviewにスタイルシートを追加してみましょう。voting.css というファイルを vendor/plugins/redmine_polls/assets/stylesheets に作成してください。:
a.vote { font-size: 120%; }
a.vote.yes { color: green; }
a.vote.no { color: red; }
Redmineを再起動すると、assetsの下はRails Enginesによって自動的に public/plugin_assets/redmine_polls/ にコピーされます。これによってWebブラウザからこれらのファイルにアクセスできるようになります。なのでassetsの下のスタイルシートやJavascriptに変更を加えた場合には必ずRedmineの再起動が必要になります。
vendor/plugins/redmine_polls/app/views/polls/index.html.erb に以下の行を加えてください。するとスタイルシートがRedmineのヘッダーからインクルードされます。:
<% content_for :header_tags do %>
<%= stylesheet_link_tag 'voting', :plugin => 'redmine_polls' %>
<% end %>
:plugin => 'redmine_polls' オプションを stylesheet_link_tag ヘルパーに渡します。
Javascript をプラグインのビューからインクルードするためにはjavascript_include_tag ヘルパーを同様に使います。
ページタイトルを設定する。¶
プラグインのviewにHTMLのタイトルを設定するには html_title ヘルパーを使います。
例:
<% html_title "Polls" -%>
プラグインをテストする¶
test/test_helper.rb:¶
テストヘルパーファイルの中に以下のように記述します。:
require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')
テストのサンプル:¶
#訳注:これ以後、本家のチュートリアルに追記されたテストに関する記述の訳ですが、ここまでと書いた人が違うようです。サンプルコードもPollsプラグインでは無くなってます。
requirements_controller_test.rb:
require File.dirname(__FILE__) + '/../test_helper'
require 'requirements_controller'
class RequirementsControllerTest < ActionController::TestCase
fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details,
:trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages,
:attachments, :custom_fields, :custom_values, :time_entries
def setup
@skill = Skill.new(:skill_name => 'Java')
@project = Project.find(1)
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
User.current = nil
end
def test_routing
assert_routing(
{:method => :get, :path => '/requirements'},
:controller => 'requirements', :action => 'index'
)
end
テスト用 DBを初期化する。:¶
以下のようなrake コマンドを実行することにより、テスト用DBを初期化することができます。:
rake db:drop:all db:create:all db:migrate db:migrate_plugins redmine:load_default_data RAILS_ENV=test
テストを実行する:¶
reqruirements_controller_test.rb のテストを行うには以下のコマンドを実行します。:
rake test:engines:all PLUGIN=redmine_requirements
ユーザおよびプロジェクトと共にテストする。¶
あなたのプラグインがプロジェクトメンバでなければ操作できない場合、functional testの最初に以下の記述を追加します。:
def setup @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end def test_index @request.session[:user_id] = 2 get :index, :project_id => 1 assert_response :success assert_template :index end
この方法が正しいのはよく判りませんが、とりあえず正しく動いているように見えます。 :S
Updated by Haru Iida over 15 years ago · 19 revisions