2018年以降の記事はGitHub Pagesに移行しました

WindowsにRedmine2.3をインストールする手順と、プラグイン作成用メモ

あらすじ

Redmine 2.0台におけるインストール方法〜起動方法とプラグインの作り方のメモ。

環境

参考サイト

Redmineインストール手順

まずは準備。

MySQL

実はMySQLさわるのはじめてかもしれない。

  • MySQL :: Download MySQL Installer からインストーラをDL。Oracleのアカウントが必要
  • 基本的にPathなどの設定はそのまま。
    • Choosing a Setup Type: Developer Default を選択
    • MySQL Server Configuration:
      • Server Configuration Type は Development Machine
      • ポートは 3306
      • root のパスワードを入力
      • Windows Service Details の Start the MySQL Server at System Startup のチェックだけ KILL そんなに使わないしPCがしょぼいので常時起動させておくこともない

全部終わると MySQL Workbench が立ち上がる。

  • Open Connection to Start Queryin に Local instance MySQL56 を選択
  • root のパスワードを入力し、ログインできる事を確認
  • コンソールから redmine ユーザを作成し、 テーブルの権限を設定する (これをよく忘れて access denied になる)
create database redmine character set utf8;
create user 'redmine'@'localhost' identified by 'my_password';
grant all privileges on redmine.* to 'redmine'@'localhost';

で、とりあえずオッケー。

Redmine
  • Redmine 2.3.1 をDLし、適当なところへ解凍。
  • config/database.yml.exampleconfig/database.yml にリネームし、内容編集。MySQLとつなげるように
production:
  adapter: mysql2
  database: redmine
  host: localhost
  username: redmine
  password: my_password
  encoding: utf8

development:
  adapter: mysql2
  database: redmine_development
  host: localhost
  username: redmine
  password: my_password
  encoding: utf8

Ruby 1.9 からMySQLにつなぐには adapter は mysql2 である必要がある模様。

  • そして bundle install --path vendor/bundle --without rmagick
    • rmagickは頑張って入れてもいいけど今回はwithoutする

MySQL アダプターがなんか言ってる…my-sql-connector-c?

(略)
Installing mysql2 (0.3.11)
(略)
Using yard (0.8.6.2)
Your bundle is complete!
Gems in the group rmagick were not installed.
It was installed into ./vendor/bundle
Post-install message from mysql2:

======================================================================================================

  You've installed the binary version of mysql2.
  It was built using MySQL Connector/C version 6.0.2.
  It's recommended to use the exact same version to avoid potential issues.

  At the time of building this gem, the necessary DLL files where available
  in the following download:

  http://dev.mysql.com/get/Downloads/Connector-C/mysql-connector-c-noinstall-6.0.2-win32.zip/from/pick

  And put lib\libmysql.dll file in your Ruby bin directory, for example C:\Ruby\bin

======================================================================================================

とりあえず落としてきて、 lib/libmysql.dllRubyのbinディレクトリにいれた。

  • セッションストア秘密鍵の作成
  • テーブルの作成
  • デフォルトのロール、トラッカー、ステータス、ワークフロー、列挙項目のロード
$ rake generate_secret_token
$ set RAILS_ENV=production
$ rake db:migrate
==  Setup: migrating ==========================================================
-- create_table("attachments", {:force=>true})
   -> 0.1700s
(略)
$ rake redmine:load_default_data

Select language: ar, az, bg, bs, ca, cs, da, de, el, en, en-GB, es, et, eu, fa, fi, fr, gl, he, hr,
hu, id, it, ja, ko, lt, lv, mk, mn, nl, no, pl, pt, pt-BR, ro, ru, sk, sl, sq, sr, sr-YU, sv, th, tr, uk, vi, zh, zh-TW [en] ja
====================================
Default configuration data loaded.
  • 起動
$ ruby script\rails server

起動したら admin/admin でログインして情報を見に行ってみる。

Environment:
  Redmine version                          2.3.1.stable
  Ruby version                             1.9.3 (i386-mingw32)
  Rails version                            3.2.13
  Environment                              production
  Database adapter                         Mysql2
Redmine plugins:
  no plugin installed

OK。

プラグイン作成の準備

コマンド

コマンドは script/rails に集約されたっぽい?

今まで script/xxx とかやっていたコマンドは script/rails xxx になっている。

$ ruby script\rails -h
bundler is found: bundle exec ruby script\rails -h
Usage: rails COMMAND [ARGS]

The most common rails commands are:
 generate    Generate new code (short-cut alias: "g")
 console     Start the Rails console (short-cut alias: "c")
 server      Start the Rails server (short-cut alias: "s")
 dbconsole   Start a console for the database specified in config/database.yml
             (short-cut alias: "db")
 new         Create a new Rails application. "rails new my_app" creates a
             new application called MyApp in "./my_app"

In addition to those, there are:
 application  Generate the Rails application code
 destroy      Undo code generated with "generate" (short-cut alias: "d")
 benchmarker  See how fast a piece of code runs
 profiler     Get profile information from a piece of code
 plugin       Install a plugin
 runner       Run a piece of code in the application environment (short-cut alias: "r")

All commands can be run with -h (or --help) for more information.
ケルトン作成

ruby script/rails generate redmine_plugin PLUGIN_NAME で作成。

  • プラグイン名はスネークケース
  • plugins/ 下に作成される
$ ruby script\rails generate redmine_plugin download_issues_with_journal
bundler is found: bundle exec ruby script\rails generate redmine_plugin download_issues_with_journal
  create  plugins/download_issues_with_journal/app
  create  plugins/download_issues_with_journal/app/controllers
  create  plugins/download_issues_with_journal/app/helpers
  create  plugins/download_issues_with_journal/app/models
  create  plugins/download_issues_with_journal/app/views
  create  plugins/download_issues_with_journal/db/migrate
  create  plugins/download_issues_with_journal/lib/tasks
  create  plugins/download_issues_with_journal/assetshttp://gosyujin.github.com/images
  create  plugins/download_issues_with_journal/assets/javascripts
  create  plugins/download_issues_with_journal/assets/stylesheets
  create  plugins/download_issues_with_journal/config/locales
  create  plugins/download_issues_with_journal/test
  create  plugins/download_issues_with_journal/test/fixtures
  create  plugins/download_issues_with_journal/test/unit
  create  plugins/download_issues_with_journal/test/functional
  create  plugins/download_issues_with_journal/test/integration
  create  plugins/download_issues_with_journal/README.rdoc
  create  plugins/download_issues_with_journal/init.rb
  create  plugins/download_issues_with_journal/config/routes.rb
  create  plugins/download_issues_with_journal/config/locales/en.yml
  create  plugins/download_issues_with_journal/test/test_helper.rb

plugins/ 下にいれば、Redmine起動時にロードしてくれる。再起動して情報を見に行くと…。

Environment:
  Redmine version                          2.3.1.stable
  Ruby version                             1.9.3 (i386-mingw32)
  Rails version                            3.2.13
  Environment                              production
  Database adapter                         Mysql2
Redmine plugins:
  download_issues_with_journal             0.0.1                 # => 増えてる!
init.rb

書き方が、Rubyのそれとちょっと違う。Rails流?なので、はじめは慣れが必要かも。

  • 文字列ではなく、なるべくシンボルを使う
  • ブロックは括弧 {} ではなく、 do, end を使う
  • メソッドの括弧 () は省略する

今は特にすることもないので、authorやurlを適当に編集したら次へ。

viewのフック

「特定の画面に何か文字とか機能を追加する」場合、viewをフックすることで実現できる。(他にも手段はあるみたいだが、とりあえず)

どこにフックできるかは、 app/views下のerbファイル を確認し、 call_hook(xxx) と書かれているところがそうらしい。詳しくは参考サイト参照

今回は、チケット一覧のページにフックしたいので、その辺を探してみる…。

すると、 app/views/issues/index.html.erb の中にこんな記述が。ページの一番下の部分にフックできそう。

<%= call_hook(:view_issues_index_bottom, { :issues => @issues, :project => @project, :query => @query }) %>

第一引数 :view_issues_index_bottom はフックする時に作成するメソッド名になる、第2引数はパラメータ。これは覚えておく。

フックファイル

PLUGIN/lib/PLUGIN_NAME/hooks.rb を作り、以下のように記載。

class Hooks < Redmine::Hook::ViewListener
  def view_issues_index_bottom(context)
    puts "view_issues_index_bottom"
    return "<p>Hello</p>"
  end
end

call_hookの第一引数になっていたとおり、 view_issues_index_bottom メソッドを作る。

次に上記のフックを読み込むために init.rb に require を追加する。

require 'download_issues_with_journal/hooks'

これで Redmine を再起動すると、チケット一覧ページに Hello と表示されているはず。

Viewファイル

また、View担当部分はきちんとViewにわけることもできる。

フック部分を以下のように変更。

class Hooks < Redmine::Hook::ViewListener
  def view_issues_index_bottom(context)
    context[:controller].send(:render_to_string, {
      :partial => "hooks/download_issues_with_journal/view_issues_index_bottom",
      :locals => context })
  end
end

:partialapp/views/ 以下のパスを指定。

上記のように指定すると app/views/hooks/download_issues_with_journal/_view_issues_index_bottom.html.erb (部分描画用のファイルは先頭に _ を付けるのがルール)が呼ばれる。中身はこんな感じ。

<div class="contextual">
  <%= @project %>
  <%= link_to("link ror", "http://rubyonrails.org") %>
</div>

チケット一覧を開いているプロジェクト名とRuby on Railsへのリンクが表示される。

これでViewをフックしつつ、Viewの定義自体はerbファイルに追い出すことができた。

Controllerと連携

ここまでViewをいじっていると、ファイル構造はこんな感じになった。

download_issues_with_journal
├─app
│  └─views
│      └─hooks
│          └─download_issues_with_journal
│              └─_view_issues_index_bottom.html.erb (3)
├─assets
├─config
├─db
├─lib
│  └─download_issues_with_journal
│      └─hooks.rb (1)
├─init.rb (2)
└─test

(1)でチケット一覧画面をフックし、(2)でそれをrequire、(3)に追加したい画面ソースを書いた。

次にController(ユーザのアクションに対応したメソッド)を作り、Viewと連携を取る。

いじるファイルは以下。

  • Controllerファイル(新規作成)
  • Viewファイル(Controllerを呼ぶように編集)
  • Routeファイル(編集)
Controller

app/controller/export_controller.rb を作成。

  • export_controller なので、、 export がこの先 :controller に指定する名前になる
  • ApplicationController クラスを継承
  • unloadable を書かないと Development モードで動かない。今はおまじないでいい
  • 処理を書いていく。メソッド名が :action となる
class ExportController < ApplicationController
  unloadable

  def export_with_journal
    puts "export_with_journal"
    send_data("aa", :type => "text/csv", :filename => "test.csv")
  end
end
View

Controller に定義した :controller と :action 名に従って、リンク先を変更する。

<div class="contextual">
  <%= link_to("dl #{@project} issues", {:controller => "export", :action => "export_with_journal"}) %>
</div>
Route

Controller と View を結びつける。

match 'projects/export/:action', :controller => 'export'

これで、ViewのリンクをたたくとControllerが呼ばれる。