Make Redmine Plugin

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

[Redmine](http://redmine.jp/)は**Ruby on Rails**で開発されたプロジェクト管理のアプリケーションです。
主にチケット管理で利用されていますが、プラグインで機能を拡張することができます。

[Ruby on Rails](http://rubyonrails.org/)の入門として[Redmine Plugin](http://www.redmine.org/projects/redmine/wiki/Plugin_Tutorial)の作り方を紹介します。
(ポイントのキーワードは[Railsドキュメント](http://railsdoc.com/)にリンクしています。)

# Ruby on Rails

最初にRuby on Railsの[特徴](http://railsdoc.com/rails_base)を簡単に説明します。

* Webアプリケーションフレームワークです。(言語はもちろんRuby)
* Model - View - Controller (MVC) アーキテクチャを採用しています。
* 設計哲学
 * DRY (Don't Repeat Yourself) : 同じことを繰り返さない
 * CoC (Convention overConfiguration) : 設定より規約

## RoRのMVC

* [Model](http://railsdoc.com/model) : ビジネスロジックやデータの操作
* [View](http://railsdoc.com/view) : 出力インターフェイスのデザイン
* [Controller](http://railsdoc.com/controller) : リクエストとレスポンスの制御

![rails_mvc](https://dl.dropboxusercontent.com/u/14690051/images/notes/lang/ruby/rails_mvc.png)


# Redmine Install

さっそくWebアプリケーション(Redmine)を動かしてみましょう。

## Download

プラグインの開発はステーブルのブランチを使いましょう。

```bash
$ git clone git://github.com/redmine/redmine.git
$ cd ./redmine/
$ git branch -r
$ git checkout 2.3-stable
```

## Configure

[Config](http://railsdoc.com/config)は`development`や`production`など環境でデータベースの接続先を変更することができます。

```bash
$ cat << __EOS__ > ./config/database.yml
development:
  adapter: sqlite3
  database: db/development.sqlite3
__EOS__
```

## Bundler

[Gemfile](http://railsdoc.com/gem)で依存するライブラリが定義されています。[bundler](http://gembundler.com/)でインストールします。
(bundlerはGemの[パッケージング](http://qiita.com/items/5b85459738d97bfa0a23)にも利用されます。)

```bash
$ bundle install --path=.bundle --without test production mysql postgresql rmagick
```

## Rake

[Rake](http://railsdoc.com/rake)はmakeに似たビルドツールです。`rake db:migrate`コマンドでデータベースにテーブルが作成されます。

```bash
$ bundle exec rake generate_secret_token
$ bundle exec rake db:migrate
$ bundle exec rake redmine:load_default_data REDMINE_LANG=en
```

コマンドの一覧はこちらで確認できます。

```bash
$ bundle exec rake -T
```


## Run

[rails server](http://railsdoc.com/rails)コマンドでWebアプリケーションを起動します。
(RailsはWEBrickというHTTPサーバが標準で提供されています。)

`http://localhost:3000/`にアクセスするとRedmineの`Home`が表示されます。

```bash
$ bundle exec rails server
```

* デフォルト管理アカウント
 * username:admin
 * password:admin 


# Generate Scaffold

Redmine Pluginを作る前にRailsのファイル構造を説明します。
[rails generate scaffold](http://railsdoc.com/rails)コマンドでファイルを自動作成します。

## Scaffold

Webアプリケーションに必要なファイルが作成されます。
(ResourceごとにModel、View、Controllerのセットがあります。)

```bash
$ bundle exec rails generate scaffold cat name:string age:integer
...
      invoke  active_record
      create    app/models/cat.rb
      invoke  resource_route
       route    resources :cats
      invoke  scaffold_controller
      create    app/controllers/cats_controller.rb
      invoke    erb
      create      app/views/cats/index.html.erb
...
```

## Tree

[ファイル構造](http://railsdoc.com/rails_base)は厳密に定義されています。

```
. 
│  config.ru
│  Gemfile
│  Rakefile
│  README
│  
├─app
│  ├─assets
│  │  ├─javascripts [ジャバスクリプト]
│  │  │      cats.js
│  │  │      
│  │  └─stylesheets [スタイルシート]
│  │          cats.css
│  │          scaffold.css
│  │          
│  ├─controllers [コントローラクラス]
│  │      account_controller.rb
│  │      cats_controller.rb
│  │      
│  ├─helpers [ビューヘルパー]
│  │      application_helper.rb
│  │      cats_helper.rb
│  │      
│  ├─models [モデルクラス]
│  │      cat.rb
│  │          
│  └─views [ビュースクリプト]
│      ├─cats
│      │      edit.html.erb [編集(ビュー)]
│      │      index.html.erb [表示(リスト)]
│      │      new.html.erb [追加(ビュー)]
│      │      show.html.erb [表示(1件)]
│      │      _form.html.erb
│      │      
│      └─layouts [レイアウト]
│              
├─config [設定情報]
│  │  database.yml  [データベース]
│  │  routes.rb [ルーティング]
│  │      
│  └─locales [言語]
│          en.yml
│          ja.yml
│          
├─db [データベース]
│  │  development.sqlite3 [データベース本体]
│  │  schema.rb [データベース]
│  │  
│  └─migrate
│          
├─doc [ドキュメント]
├─lib [ライブラリ]
├─log [ログの出力先]
├─public [公開フォルダ]
├─script [ジェネレータースクリプトなど]
├─test [テストスクリプトなど]
└─tmp [テンポラリファイル]
```

## Run

`rake db:migrate`コマンドで`cats`テーブルが作成されます。
`http://localhost:3000/cats`にアクセスすると`Listing cats`が表示されます。

```bash
$ bundle exec rake db:migrate
$ bundle exec rails server
```

# Migration

データベースのテーブルを管理する仕組みに[マイグレーション](http://railsdoc.com/migration)を採用しています。
さきほどのScaffoldで`cats`テーブルを作成するマイグレーションファイルが作成されています。

```ruby
class CreateCats < ActiveRecord::Migration
  def change
    create_table :cats do |t|
      t.string :name
      t.integer :age

      t.timestamps
    end
  end
end
```

`rake db:migrate`コマンドでマイグレーションファイルが処理されます。
(データベースはSQLite3以外にもMySQLやPostgreSQLなど利用できます。 )

```bash
$ sqlite3 ./db/development.sqlite3 
sqlite> .schema cats
CREATE TABLE "cats" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
"name" varchar(255), 
"age" integer, 
"created_at" datetime NOT NULL, 
"updated_at" datetime NOT NULL);
```

データベースの構成は`schema.rb`ファイルに定義されます。
(O/Rマッピングでデータを操作するので、データベースの種類やSQLなどは意識しません。)

```ruby
create_table "cats", :force => true do |t|
  t.string   "name"
  t.integer  "age"
  t.datetime "created_at", :null => false
  t.datetime "updated_at", :null => false
end
```


# Generate Redmine Plugin

Redmine PluginにもGenerateがあります。試しに***Redmine Animal***プラグインを作成します。

## Scaffold

Controllerを作成するとViewも作成されます。

```bash
$ bundle exec rails generate redmine_plugin redmine_animal
$ bundle exec rails generate redmine_plugin_controller redmine_animal animal_cats index show
$ bundle exec rails generate redmine_plugin_model redmine_animal animal_cat name:string age:integer
```

## Tree

`rails generate scaffold`コマンドで作成されたファイル構造とほぼ同じです。
(規約を覚えると誰でも簡単にコードを読むことができるのはポイントです。)

```
.
│  init.rb [初期化ファイル]
│  README.rdoc
│
├─app
│  ├─controllers [コントローラクラス]
│  │      animal_cats_controller.rb
│  │
│  ├─helpers [ビューヘルパー]
│  │      animal_cats_helper.rb
│  │
│  ├─models [モデルクラス]
│  │      animal_cat.rb
│  │
│  └─views[ビュースクリプト]
│      └─animal_cats
│              index.html.erb
│              show.html.erb
│
├─assets
│  ├─images
│  ├─javascripts [ジャバスクリプト]
│  └─stylesheets [スタールシート]
├─config
│  │  routes.rb [ルーティング]
│  │
│  └─locales [言語]
│          en.yml
│
├─db
│  └─migrate
│          001_create_animal_cats.rb
│
├─lib [ライブラリ]
└─test [テストスクリプトなど]
```

## Routing

[ルーティング](http://railsdoc.com/routes)を設定します。[routes.rb](http://guides.rubyonrails.org/routing.html)ファイルに設定します。
URLにコントローラとアクション(コントローラのメソッド)を指定します。

`resources :cats`だとURLは`/cats`でコントローラは`cats_controller.rb`ファイルです。
(アクションはCRUDの操作に対応しています。また、RESTfulなURLを提供しています。)

| HTTP Verb |  Path          | action  | used for     |
|:----------|:---------------|:--------|:-------------|
| GET       | /cats          | index   | 表示(リスト) |
| GET       | /cats/new      | new     | 追加(ビュー) |
| POST      | /cats          | create  | 作成         |
| GET       | /cats/:id      | show    | 表示(1件)    |
| GET       | /cats/:id/edit | edit    | 編集(ビュー) |
| PUT       | /cats/:id      | update  | 更新         |
| DELETE    | /cats/:id      | destroy | 削除         |

このルートは`/animal/cats/`のURLで一覧が表示されます。

```bash
$ cat << __EOS__ > ./plugins/redmine_animal/config/routes.rb
RedmineApp::Application.routes.draw do
  scope '/animal', as: :animal do
    resources :cats, controller: :animal_cats
  end
end
__EOS__
```

ルートの一覧はこちらで確認できます。

```bash
$ bundle exec rake routes
```

## Run

`rake redmine:plugins:migrate`コマンドで`animal_cats`テーブルが作成されます。
`http://localhost:3000/animal/cats`にアクセスすると`AnimalCatsController`が表示されます。

```bash
$ bundle exec rake redmine:plugins:migrate
$ bundle exec rails server
```

## Adjust

Scaffoldの`cat`で作成したファイルを`sed`コマンドなどでコピーします。
今回は`cat`を`animal_cat`に置換えるだけで動作します。規約通りです。(ｷﾘｯ

コントローラをコピーします。

```bash
$ sed 's/Cat/AnimalCat/g' ./app/controllers/cats_controller.rb > ./plugins/redmine_animal/app/controllers/animal_cats_controller.rb 
$ cd ./plugins/redmine_animal/app/controllers
$ cat animal_cats_controller.rb |(rm animal_cats_controller.rb ;sed 's/:cat/:animal_cat/g' > animal_cats_controller.rb)
$ cat animal_cats_controller.rb |(rm animal_cats_controller.rb ;sed 's/cats_url/animal_cats_url/g' > animal_cats_controller.rb)
```

ビューをコピーします。

```bash
$ sed 's/cat_path/animal_cat_path/g' ./app/views/cats/index.html.erb > ./plugins/redmine_animal/app/views/animal_cats/index.html.erb
$ sed 's/cat_path/animal_cat_path/g' ./app/views/cats/show.html.erb > ./plugins/redmine_animal/app/views/animal_cats/show.html.erb
$ sed 's/cats_path/animal_cats_path/g' ./app/views/cats/new.html.erb > ./plugins/redmine_animal/app/views/animal_cats/new.html.erb
$ sed 's/cats_path/animal_cats_path/g' ./app/views/cats/edit.html.erb > ./plugins/redmine_animal/app/views/animal_cats/edit.html.erb
$ cp ./app/views/cats/_form.html.erb  ./plugins/redmine_animal/app/views/animal_cats/
```

# Locale

[国際化対応](http://guides.rubyonrails.org/i18n.html)で日本語は`/config/locales/ja.yml`ファイルに追加します。

```bash
$ cat << __EOS__ > ./plugins/redmine_animal/config/locales/ja.yml
ja:
  field_age: "年齢"
__EOS__
```

# Redmine Menu

最後にRedmineに[メニュー](http://www.redmine.org/projects/redmine/wiki/Plugin_Tutorial#Extending-menus)を表示します。(今回はアプリケーションメニューにしました。)

```bash
$ cat << __EOS__ > ./plugins/redmine_animal/init.rb
Redmine::Plugin.register :redmine_animal do
  name 'Redmine Animal plugin'
  author 'Author name'
  description 'This is a plugin for Redmine'
  version '0.0.1'
  url 'http://example.com/path/to/plugin'
  author_url 'http://example.com/about'

  menu :application_menu, :animal, {controller: :animal_cats, action: :index}
end
__EOS__
```

メニューの`Animal`をクリックすると`Listing cats`が表示されます。

![animal_cat_base](https://dl.dropboxusercontent.com/u/14690051/images/notes/its/redmine/example/animal_cat_base.png)


Redmineは認証・認可の仕組みが標準で実装されているので、業務アプリケーションも簡単に作れます。
[次回](http://qiita.com/items/fe139ceb93ad13794323)はScaffoldで出力されたファイルを修正しながらModel - View - Controller (MVC)を紹介します。


# Tips

RailsはHTML以外のXML、JSON、CSVなどをレスポンス処理で対応しています。
例えば、URLの末に`.json`を付けるとJSON形式で出力されます。

```bash
$ curl http://localhost:3000/animal/cats.json
[{"animal_cat":{"age":2,"id":1,"name":"もも"}},{"animal_cat":{"age":0,"id":2,"name":"クロ"}}]
```