はじめに
この記事は,Redmine プラグイン作成ガイド「r-labs | Rails を知らない人のための Redmine プラグイン開発ガイド」を Redmine3.4 & Redmine4.0 で実行した際に,Ruby, Rails 初心者の私がつまずいて変更した点をまとめたものです.元記事に対して変更の必要がないと判断した部分は変更なしと記しました.
ハッシュの記法はプラグイン開発ガイドに倣い,:key => value
で統一しています.
プラグイン開発ガイド元記事(Redmine 2.1〜2.3 を前提):
https://www.r-labs.org/projects/r-labs/wiki/プラグイン開発ガイド
環境
- Windows 10 64bit Ver.1903
- Bitnami Redmine Stack 3.4.6-5
- Rails 4.2.8
- ruby 2.3.3p222 (2016-11-21 revision 56859) [i386-mingw32]
- Bitnami Redmine Stack 4.0.3-3
- Rails 5.2.2.1
- ruby 2.5.5p157 (2019-03-15 revision 67260) [x64-mingw32]
- (私の環境では最新の Bitnami Redmine Stack 4.0.4 を動作させることが出来ませんでした.)
Redmine3.4(Rails4.2) と Redmine4.0(Rails5.2) での変更点
- マイグレーションファイルの修正
- before_filter メソッドの廃止に伴い,before_action メソッドを利用
目次(プラグイン開発ガイドより)
- はじめに
- プラグイン開発環境の準備
- Rails の概要
- サンプルプラグインの仕様
- プラグインスケルトンの生成
- init.rb の作成
- モデルのスケルトンの生成
- コントローラのスケルトンの生成
- プロジェクトで利用可能にする
- 国際化
- 一覧表示 アクション
- 新規作成 アクション
- その他のアクション(詳細表示、編集フォーム、更新、削除、プレビュー)
- まとめ
r-labs プラグイン開発ガイドを bitnami Redmine 3.4 へ適用した際の変更点まとめ
1. はじめに
変更なし
2. プラグイン開発環境の準備
開発用 Redmine のポイント
変更なし
使用ソフト
この記事では Bitnami Redmine を使用しました.
https://bitnami.com/stack/redmine/installer
gem パッケージのインストール
実行しません.
データベース設定
以下の記事を参考にさせていただき,development モードで起動させるためのデータベースの設定を進めます.
参考: Redmine pluginの開発について当初自分が疑問に思ってたことに回答 - Qiita
疑問2 どうやってdevelopmentモードやtestモードで動かすの?
コンソールを起動
C:\Bitnami\redmine-3.4.6-5\use_redmine.bat
cd .\apps\redmine\htdocs
Redmineをdevelopmentモードで起動する
起動中のサービスを停止
→ 停止しなくても問題ない相対パスの無効化
development用、test用bundle設定有効化
→ development だけ除く```:.\.bundle\config BUNDLE_WITHOUT: test:sqlite ```
- bundle実行
- DB設定を確認
```yml:.\config\database.yml production: adapter: mysql2 database: bitnami_redmine host: 127.0.0.1 username: bitnami password: de0166b709 # インストール時に自動生成 encoding: utf8 port: 3306 development: adapter: mysql2 database: bitnami_redmine host: 127.0.0.1 username: bitnami password: de0166b709 # インストール時に自動生成 encoding: utf8 port: 3306
データベースの作成
Bitnami インストール時に作成済みのため実行しません.
サーバの起動
> bundle exec rails s
localhost:3000 へアクセスすると Redmine が表示されます.
補足: log について
development 環境では,↑のように Terminal で log が確認出来ますが,logファイル(.\log\development.log
)も参考になりました.個人的に,Terminal 上の出力結果は,画面端で文字が折返されてしまうために文字の列が揃っておらず見難いと感じています.
3. Rails の概要
変更なし
4. サンプルプラグインの仕様
変更なし
5. プラグインスケルトンの生成
プラグイン名前を決める
変更なし(ガイドと同じく redmine_standard
とします)
スケルトン
変更なし
スケルトン作成コマンドの実行
ruby script/rails
→ bundle exec rails
> bundle exec rails generate redmine_plugin redmine_standard
create plugins/redmine_standard/app
create plugins/redmine_standard/app/controllers
create plugins/redmine_standard/app/helpers
create plugins/redmine_standard/app/models
create plugins/redmine_standard/app/views
create plugins/redmine_standard/db/migrate
create plugins/redmine_standard/lib/tasks
create plugins/redmine_standard/assets/images
create plugins/redmine_standard/assets/javascripts
create plugins/redmine_standard/assets/stylesheets
create plugins/redmine_standard/config/locales
create plugins/redmine_standard/test
create plugins/redmine_standard/test/fixtures
create plugins/redmine_standard/test/unit
create plugins/redmine_standard/test/functional
create plugins/redmine_standard/test/integration
create plugins/redmine_standard/README.rdoc
create plugins/redmine_standard/init.rb
create plugins/redmine_standard/config/routes.rb
create plugins/redmine_standard/config/locales/en.yml
create plugins/redmine_standard/test/test_helper.rb
プラグインのディレクトリ構成
> tree /F plugins/redmine_standard
│ init.rb
│ README.rdoc
│
├─app
│ ├─controllers
│ ├─helpers
│ ├─models
│ └─views
├─assets
│ ├─images
│ ├─javascripts
│ └─stylesheets
├─config
│ │ routes.rb
│ │
│ └─locales
│ en.yml
│
├─db
│ └─migrate
├─lib
│ └─tasks
└─test
│ test_helper.rb
│
├─fixtures
├─functional
├─integration
└─unit
6. init.rb の作成
変更なし
7. モデルのスケルトンの生成
データベース
変更なし
モデルの名前とデータ構成を決める
変更なし
モデルスケルトンの生成
ruby script/rails
→ bundle exec rails
> bundle exec rails generate redmine_plugin_model redmine_standard foo project_id:integer subject:string description:text
create plugins/redmine_standard/app/models/foo.rb
create plugins/redmine_standard/test/unit/foo_test.rb
create plugins/redmine_standard/db/migrate/001_create_foos.rb
生成された Migration 用のファイル
Redmine 3.4
変更なし
Redmine 4.0
Redmine 3.4 (Rails 4.2) と同じ記述ではエラーが発生し,マイグレーションを完了できません.
>bundle exec rake redmine:plugins:migrate
rake aborted!
StandardError: An error has occurred, all later migrations canceled:
Directly inheriting from ActiveRecord::Migration is not supported. Please specify the Rails release the migration was written for:
class CreateFoos < ActiveRecord::Migration[4.2]
これは,Rails 5.1 以降 Migration versioning により,対象とするバージョンの記載が必須となったため...だそうです.
参考: Rails Migration versioningと5.1での変更点 - chulip.org
警告メッセージにある通り変更します.
# class CreateFoos < ActiveRecord::Migration # Rails 4.2
class CreateFoos < ActiveRecord::Migration[4.2] # Rails 5.2
def change
create_table :foos do |t|
t.integer :project_id
t.string :subject
t.text :description
end
end
end
Migration の実行
ruby script/rails
→ bundle exec rails
> bundle exec rake redmine:plugins:migrate
Migrating redmine_standard (Redmine Standard plugin)...
== 1 CreateFoos: migrating ====================================================
-- create_table(:foos)
-> 0.0322s
== 1 CreateFoos: migrated (0.0339s) ===========================================
※Migration の実行時にRAILS_ENV
オプションをつけない場合,development
環境に対してテーブルが作成されます.(参考: rake db:migrate - リファレンス - - Railsドキュメント)
本来であればproduction
環境にテーブルを作成するにはRAILS_ENV=production
オプションをつける必要がありますが,今回はproduction
環境とdevelopment
環境のDBを同一として設定したため,development
環境でfoos
テーブルを作ればproduction
環境でもfoos
テーブルが使えることになります.
生成された Model のファイル
変更なし
プラグインのテーブルの削除
変更なし
sqlite3 によるデータベースの操作
Bitnami Redmine は MySQL のため,MySQLに置き換えて考えます.
データベース一覧表示
> mysql -u root -p
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| bitnami_redmine |
| mysql |
| performance_schema |
| test |
+--------------------+
5 rows in set (0.00 sec)
bitnami_redmine テーブル一覧表示
foos テーブルが作られている事が確認できます
mysql> show tables from bitnami_redmine;
+-------------------------------------+
| Tables_in_bitnami_redmine |
+-------------------------------------+
| attachments |
| auth_sources |
:
| enabled_modules |
| enumerations |
| foos |
| groups_users |
| import_items |
:
| wikis |
| workflows |
+-------------------------------------+
56 rows in set (0.00 sec)
8. コントローラのスケルトンの生成
コントローラ、アクションの名前を決める
変更なし(ガイドと同一とします)
コントローラのスケルトン作成コマンドの実行
ruby script/rails
→ bundle exec rails
> bundle exec rails generate redmine_plugin_controller redmine_standard foos index new show edit
create plugins/redmine_standard/app/controllers/foos_controller.rb
create plugins/redmine_standard/app/helpers/foos_helper.rb
create plugins/redmine_standard/test/functional/foos_controller_test.rb
create plugins/redmine_standard/app/views/foos/index.html.erb
create plugins/redmine_standard/app/views/foos/new.html.erb
create plugins/redmine_standard/app/views/foos/show.html.erb
create plugins/redmine_standard/app/views/foos/edit.html.erb
コントローラの生成ファイル
変更なし
ビューの生成ファイル
変更なし
Erb (Embeded ruby)
変更なし
9. プロジェクトで利用可能にする
モジュールと permission の設定
変更なし
プラグインメニューへの追加
変更なし
URL の指定方法
変更なし
Rails の機能
変更なし
ルーティング
ルーティングの設定
後に preview_link
メソッドにより使用することになる preview
URLは,PATCH
メソッドで処理されるため,put 'preview', :on => :member
→ patch 'preview', :on => :member
へ変更します.
(post 'preview', :on => :collection
は,元記事のガイドでは使用していないので検証しませんでした.)
# Plugin's routes
# See: http://guides.rubyonrails.org/routing.html
Rails.application.routes.draw do
resources :projects do
resources :foos do
post 'preview', :on => :collection
# put 'preview', :on => :member # プラグイン開発ガイドに記載されている設定
patch 'preview', :on => :member # プラグイン開発ガイドより変更
end
end
end
ルーティングの確認
ruby script/rails
→ bundle exec rails
> bundle exec rake routes
Prefix Verb URI Pattern Controller#Action
preview_project_foos POST /projects/:project_id/foos/preview(.:format) foos#preview
preview_project_foo PATCH /projects/:project_id/foos/:id/preview(.:format) foos#preview
project_foos GET /projects/:project_id/foos(.:format) foos#index
POST /projects/:project_id/foos(.:format) foos#create
new_project_foo GET /projects/:project_id/foos/new(.:format) foos#new
edit_project_foo GET /projects/:project_id/foos/:id/edit(.:format) foos#edit
project_foo GET /projects/:project_id/foos/:id(.:format) foos#show
PATCH /projects/:project_id/foos/:id(.:format) foos#update
PUT /projects/:project_id/foos/:id(.:format) foos#update
DELETE /projects/:project_id/foos/:id(.:format) foos#destroy
Prefix | Verb | URI Pattern | Controller#Action |
---|---|---|---|
preview_project_foos | POST | /projects/:project_id/foos/preview(.:format) | foos#preview |
preview_project_foo | PATCH | /projects/:project_id/foos/:id/preview(.:format) | foos#preview |
project_foos | GET | /projects/:project_id/foos(.:format) | foos#index |
POST | /projects/:project_id/foos(.:format) | foos#create | |
new_project_foo | GET | /projects/:project_id/foos/new(.:format) | foos#new |
edit_project_foo | GET | /projects/:project_id/foos/:id/edit(.:format) | foos#edit |
project_foo | GET | /projects/:project_id/foos/:id(.:format) | foos#show |
PATCH | /projects/:project_id/foos/:id(.:format) | foos#update | |
PUT | /projects/:project_id/foos/:id(.:format) | foos#update | |
DELETE | /projects/:project_id/foos/:id(.:format) | foos#destroy |
index ページの表示
変更なし
@project の設定
変更なし
before_filter
Redmine 3.4
変更なし
Redmine 4.0
before_filter
を使用するとエラーとなります.
(ブラウザ上でエラーの詳細内容を確認出来ます)
警告メッセージの通りbefore_action
に変更します.
class FoosController < ApplicationController
unloadable
menu_item :standard
# before_filter :find_project, :authorize # Rails 4.2
before_action :find_project, :authorize # Rails 5.2
# before_filter :find_foo, :except => [:index, :new, :create, :preview] # Rails 4.2
before_action :find_foo, :except => [:index, :new, :create, :preview] # Rails 5.2
:
authorize
変更なし
途中経過①
標準プラグインIndex(index アクション)
プロジェクト > モジュール設定ページ
管理 > ロールと権限 設定ページ
10. 国際化
変更なし
11. 一覧表示 アクション
ページ表示の流れ
変更なし
コントローラの実装
Foo.find
の代わりに Foo.where
を使用します.
def index
# @foos = Foo.find(:all, :conditions => ["project_id = #{@project.id} "]) # プラグイン開発ガイドに記載されているスクリプト
# データが空の場合↓のようなエラーが発生する
# Couldn't find all Foos with 'id': (all, {:conditions=>["project_id = 1 "]}) (found 0 results, but was looking for 2)
@foos = Foo.where("project_id = #{@project.id}") # エラー対策
end
ビューの実装
変更なし
一覧表示ページ
変更なし
途中経過②
標準プラグインIndex(index アクション)
12. 新規作成(new)アクション
新規作成ページの仕様
変更なし
GET と POST と PUT
変更なし
コントローラの実装
params[:foo]
→ params[:foo].permit(:subject, :description)
とします.
参考: 【Rails】パラメータからcreateするときにはまったところメモ - Qiita
def create
# @foo = Foo.new(params[:foo]) # プラグイン開発ガイドに記載されているスクリプト
# ↓のようなエラーが発生する
# ActiveModel::ForbiddenAttributesError
@foo = Foo.new(params[:foo].permit(:subject, :description)) # エラー対策
@foo.project_id = @project.id
if @foo.save
flash[:notice] = l(:notice_successful_create)
redirect_to project_foo_path(@project, @foo.id)
end
end
その他のエラー
create
メソッドを追加したにも関わらず AbstractController::ActionNotFound (The action 'create' could not be found for FoosController)
エラーが発生する場合,create
メソッドが private
メソッドになっている可能性があります.(私は一度ミスしました….)
ビューの実装
変更なし
モデルの実装
変更なし
途中経過③
新規作成(new アクション)
作成完了(create アクション)
13. その他のアクション(詳細表示、編集フォーム、更新、削除、プレビュー)
Foo オブジェクト(@foo)の取得
変更なし
詳細表示(show アクション)
:confirm => l(:text_are_you_sure)
→ :data => {:confirm => l(:text_are_you_sure)}
とします.
※ :confirm =>
はRails4.1で廃止された模様です.
(参考: Redmine 4.0(Rails 5.1)でのプラグイン作成について - torutkのブログ)
<h2><%=h l(:label_foo) %>#<%= @foo.id %></h2>
<div class="issue">
<div class="subject">
<h3><%= @foo.subject %></h3>
</div>
<% unless @foo.description.blank? %>
<p><strong><%=l(:field_description)%></strong></p>
<div class="wiki">
<%= textilizable @foo.description %>
</div>
<% end %>
</div>
<div class="contextual">
<%= link_to_if_authorized(l(:button_edit),
{:action => 'edit', :project_id => @project, :id => @foo.id},
:class => 'icon icon-edit') %>
<%= link_to_if_authorized(l(:button_delete),
{:action => 'destroy', :project_id => @project, :id => @foo.id},
# :confirm => l(:text_are_you_sure), # Rails4.1で廃止
:data => {:confirm => l(:text_are_you_sure)}, # 対策
:method => :delete,
:class => 'icon icon-del') %>
</div>
削除(destroy アクション)
変更なし
編集(edit アクション)
project_foo_path(@project)
→ project_foo_path(@project, @foo.id)
とします(2箇所).
(→ 過去の Redmine では動くのでしょうか?疑問です.)
<h2><%=h l(:label_foo) %>#<%= @foo.id %></h2>
<%= labelled_form_for :foo, @foo,
# :url => project_foo_path(@project), # No route matches となる
:url => project_foo_path(@project, @foo.id), # 対策
:html => {:multipart => true, :id => 'foo-form'} do |f| %>
<%= render :partial => 'foos/form', :locals => {:form => f} %>
<%= f.submit l(:button_edit) %>
<% #= preview_link( preview_project_foo_path(@project), 'foo-form' ) %>
<% # ↑ No route matches となる. 対策↓ %>
<%= preview_link( preview_project_foo_path(@project, @foo.id), 'foo-form' ) %>
<% end %>
<div id="preview" class="wiki"></div>
更新(update アクション)
new アクション同様に params[:foo]
→ params[:foo].permit(:subject, :description)
とします.
def update
# @foo.attributes = params[:foo] # プラグイン開発ガイドに記載されているスクリプト
# ↓のようなエラーが発生する
# ActiveModel::ForbiddenAttributesError
@foo.attributes = params[:foo].permit(:subject, :description) # エラー対策
if @foo.save
flash[:notice] = l(:notice_successful_update)
redirect_to project_foo_path(@project, @foo.id)
end
rescue ActiveRecord::StaleObjectError
flash.now[:error] = l(:notice_locking_conflict)
end
プレビュー(preview アクション)
変更なし ※Redmine 4.0 では既に廃止となっている機能です.
レイアウト
変更なし
途中経過④
詳細表示(show アクション)
編集(edit アクション) & プレビュー(preview アクション)
削除(destroy アクション)
Index(index アクション)
14. まとめ
変更なし
おわりに
今回,チュートリアル(開発ガイド)として内容が充実していると感じた「r-labs | Rails を知らない人のための Redmine プラグイン開発ガイド」を参考にさせていただきました.
このチュートリアルは,対象とするRedmineのバージョンが古いためか(Redmine 2.1〜2.3 を前提),記事の通りに実行してもすんなりとは動作せず,一つ一つ動作を調べながら進めていくこととなりました.
結果として時間はかかってしまいましたが,Ruby, Rails, Redmine について知識を深める良い機会になったと感じています.
参考になりましたら幸いです.