はじめに
RedmineはRuby on Railsで実装されたプロジェクト管理ツールです。競合のツールとしてTracが有名ですが、
これにより今年から本格的にRedmineへの移行が始まっていくと思われます。既に2009年の9月にはオープンソースのSNSエンジンであるOpenPNEの開発チームがTracからRedmineに移行したことや、
今回は、
Redmineのインストール
Redmineのインストール方法は公式サイトの記事を始め、
$ wget http://rubyforge.org/frs/download.php/69449/redmine-0.9.3.tar.gz $ tar zxf redmine-0.9.3.tar.gz; cd redmine-0.9.3
$ mysql -u root -p -e 'create database redmine character set utf8'
$ cp config/database.yml.example config/database.yml
$ vi config/database.yml
※ お使いのDBMSに従ってデータベースのアカウント情報を入力して下さい。
$ RAILS_ENV=production rake db:migrate
$ RAILS_ENV=production rake db:migrate
$ RAILS_ENV=production rake redmine:load_default_data
※ 言語選択のプロンプトが表示されるので、「ja」と入力します。
$ sudo script/server -p 80 -e production
作ってみよう
さて、
プラグインの開発は、
- 雛形の作成
- プラグインの初期設定
- モデルの実装
- マイグレーションの実施
- コントローラ・
ビューの実装
今回作成するプラグインの仕様
今回はServerStatusというプラグインを作ります。稼動しているサーバのステータスを一覧で確認することで、
雛形の作成
Redmineではプラグインの実装用に3つのジェネレータが用意されています。
- redmine_
plugin - redmine_
plugin_ controller - redmine_
plugin_ model
雛形の作成にはredmine_
$ ruby script/generate redmine_plugin ServerStatus
REDMINE_
プラグインの初期設定
PLUGIN_
- トップメニュー
(top_ menu) - アカウントメニュー
(account_ menu) - アプリケーションメニュー
(application_ menu) - プロジェクトメニュー
(project_ menu)
それぞれのメニューの表示箇所を下図に表示します。なお、
![図1 トップメニュー、アカウントメニュー、プロジェクトメニュー 図1 トップメニュー、アカウントメニュー、プロジェクトメニュー](/assets/images/dev/serial/01/ruby/0034/thumb/TH800_001.jpg)
![図2 アプリケーションメニュー 図2 アプリケーションメニュー](/assets/images/dev/serial/01/ruby/0034/thumb/TH800_002.jpg)
今回はトップメニューに追加します。メニューにはラベルとURLを指定する必要があります。URLはHashでも文字列でも構いませんが
require 'redmine'
Redmine::Plugin.register :redmine_server_status do
name 'Redmine Server Status plugin'
author 'Takayuki Kyowa'
description 'Redmine Server Status plugin'
version '0.0.1'
menu :top_menu, :server_list, { :controller => 'servers', :action => 'index' }, :caption => "サーバ一覧", :last => true
end
最後のmenuメソッドでメニューへの追加先を指定しています。引数は以下のとおりです。
menu
:top_menu, # 追加先メニュー名
:server_list, # メニュー項目の識別子。一意でなければならない。
{ :controller => 'contributions', :action => 'index' }, # URLのハッシュ、または文字列。
:caption => "サーバ一覧", # メニューの項目名
:last => true # メニューの追加先。標準メニューの間や先頭に挿入することも可能です。
余談ですが、
Redmine::MenuManager.map :top_menu do |menu|
menu.push :home, :home_path
menu.push :my_page, { :controller => 'my', :action => 'page' }, :if => Proc.new { User.current.logged? }
menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural
menu.push :administration, { :controller => 'admin', :action => 'index' }, :if => Proc.new { User.current.admin? }, :last => true
menu.push :help, Redmine::Info.help_url, :last => true
end
Redmine::Plugin.
モデルの実装
次にモデルを作成します。今回必要になるのはサーバとサーバのステータス変更履歴を表現する二つのモデルです。
通常はそれぞれでテーブルを作成しますが、
redmine_
$ ruby script/generate redmine_plugin_model ServerStatus Server name:string, status:integer, comment_counts:integer
redmine_
redmine_plugin_model <plugin_name> <model_name> [ <column_name:column_type>, ...]
なお、
モデルにリレーションや基本的なロジックを記述していきます。
class Server < ActiveRecord::Base
has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on DESC"
module Status
WORKING = 1
STOPPED = 2
end
def status_name
case self.status
when Status::WORKING
"稼働中"
when Status::STOPPED
"停止"
end
end
end
マイグレーション
次にマイグレーションと初期データを投入します。
モデルを作成した時点でPLUGIN_
mv ${PLUGIN_ROOT}/db/migrate/20100301102344_create_servers.rb ${PLUGIN_ROOT}/db/migrate/001_create_servers.rb
また、
class CreateServers < ActiveRecord::Migration
def self.up
create_table :servers do |t|
t.column :name, :string
t.column :status, :integer
t.column :comments_count, :integer, :default => 0
end
(1..8).each{|i| Server.create!(:name => sprintf("server%02d", i), :status => Server::Status::WORKING)}
end
def self.down
drop_table :servers
end
end
一通りの修正が完了したらマイグレーションを実施します。
$ rake db:migrate_plugins
コントローラ・ビューの実装
さて、
まずはredmine_
$ ruby script/generate redmine_plugin_controller ServerList servers index
PLUGIN_
次にコントローラの実装です。Serverモデルからすべてのレコードを名前順に取得します。なお、
class ServersController < ApplicationController
def index
@servers = Server.find(:all, :order => "name ASC")
end
end
次にビューです。@servers変数を展開してサーバ名とステータスを書き出しています。
<style type="text/css">
table.servers {
width: 60%;
}
</style>
<h2>サーバ一覧</h2>
<table class="list servers"> <!-- ① -->
<thead><tr>
<th>サーバ名</th>
<th>状態</th>
</tr></thead>
<tbody>
<%- @servers.each do |server| -%>
<tr class="<%= cycle("odd", "even") %> server">
<td><%=h server.name %></td>
<td><%=h server.status_name %></td>
</tr>
<% end %>
</tbody>
</table>
①ではテーブルのclass属性にlistを指定しています。このクラスはチケットの一覧画面など、
これで準備完了です。アプリケーションサーバを再起動してブラウザをリロードしてみましょう。トップメニューに
![図3 サーバ一覧画面 図3 サーバ一覧画面](/assets/images/dev/serial/01/ruby/0034/thumb/TH800_003.jpg)
ステータス変更機能の実装
では今度はステータスの変更機能を実装していきます。アクション名はtoggleとし、
まずはコントローラのコードです。
def toggle
if request.xhr? && request.post?
server = Server.find(params[:id])
server.update_attributes!(:status => server.status ^ 3)
user = User.current # ①
comment = Comment.new(:comments => "#{user.login}さんが#{server.status_name}に変更しました。", :author => user)
server.comments << comment
render :update do |page|
page.replace_html "status_#{server.id}", server.status_name
page.visual_effect :shake, "status_#{server.id}"
end
end
end
①のUser.
次にビューのコードです。AJAXに対応するため、
<%- @servers.each do |server| -%>
<tr class="<%= cycle("odd", "even") %> server">
<td><%=h server.name %></td>
<td><%= link_to_remote content_tag(:span, h(server.status_name), :id => "status_#{server.id}"), :url => { :action => "toggle", :id => server.id }, :method => "post" %></td>
</tr>
<%- end -%>
履歴の確認機能の実装
最後に履歴の確認画面を作ります。アクション名はshowとします。これも特にRedmineとは関連しないため、 これで一通りの実装が完了しました。こんな感じの画面になります。 今回は基本的なプラグインの開発方法を解説しました。ここまで見ていただいたように、 RedmineやTracなどのプロジェクト管理ツールはプロジェクトのポータルページを兼ねることが多いと思います。そこに手軽に自作のシステムを組み込むことができる、 次回はワークフローとデプロイタスクを統合するContinuousDeploymentというプラグインを作成します。チケットやタイムラインとの連動についても解説していきますので、
def show
@server = Server.find(params[:id], :include => [:comments])
end
<%- @servers.each do |server| -%>
<tr class="<%= cycle("odd", "even") %> server">
<td><%= link_to h(server.name), :action => 'show', :id => server.id %></td>
<td><%= link_to_remote content_tag(:span, h(server.status_name), :id => "status_#{server.id}"), :url => { :action => "toggle", :id => server.id }, :method => "post" %></td>
</tr>
<%- end -%>
<h2><%=h @server.name %>のステータス変更履歴</h2>
<%- @server.comments.each do |comment| -%>
<p><%=h comment.created_on.strftime("%F %T") %> : <%=h comment.comments %></p>
<%- end -%>
まとめ