1. saitoxu

    Posted

    saitoxu
Changes in title
+Redmine3.2プラグイン開発入門 (3) - Redmineのメソッドをカスタマイズをする
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,185 @@
+Redmine3.2プラグイン開発入門の第3弾です!
+
+前回の内容: [Redmine3.2プラグイン開発入門 (2) - 既存画面に項目を追加する](http://qiita.com/saitoxu/items/45c2d66541126660790a)
+
+今回は**Redmine本体のメソッドをカスタマイズ**します。
+
+# Redmineのメソッドをカスタマイズ
+前回チケットの参照画面にviewを追加しましたが、チケットに紐づいたテストデータの読込/更新が実装されていませんでした。
+そこで今回はRailsの機能であるalias_method_chainを使って既存メソッドをカスタマイズし、チケットデータを読み込む際にテストデータも読み込むようにします。
+alias_method_chainの説明は[こちら](http://www.techscore.com/blog/2013/02/27/rails-alias_method_chain-%E6%97%A2%E5%AD%98%E3%81%AE%E5%87%A6%E7%90%86%E3%82%92%E4%BF%AE%E6%AD%A3%E3%81%99%E3%82%8B%E5%B8%B8%E5%A5%97%E6%89%8B%E6%AE%B5/)の記事によく書かれているので、本稿ではRedmineのプラグイン開発におけるalias_method_chainの利用方法に説明を絞ります。
+
+# modelの作成
+まずは読み込み元となるmodelを作成します。
+
+```bash:
+# modelの作成
+# issue_id: チケットID, content: テスト内容, result: テスト結果
+bundle exec rails g redmine_plugin_model sample Test issue_id:integer content:text result:integer
+# マイグレーション
+bundle exec rake redmine:plugins:migrate RAILS_ENV=production
+```
+
+# patchモジュールの作成
+チケットの参照画面の読み込み時にテストデータも同時に読み込むよう、
+IssuesControllerクラスのpatchモジュールを作成しshowメソッドに処理を加えます。
+
+```rb:lib/sample/issues_controller_patch.rb
+module Sample
+ module IssuesControllerPatch
+ def self.included(base)
+ base.send(:include, InstanceMethods)
+
+ base.class_eval do
+ unloadable
+
+ alias_method_chain :show, :test
+ end
+ end
+
+ module InstanceMethods
+ def show_with_test
+ # チケットに紐づいたテストデータがあれば取得
+ @test = Test.find_by(issue_id: @issue.id)
+ if @test.nil?
+ # なければ新規作成
+ @test = Test.create!(issue_id: @issue.id, content: "", result: 0)
+ end
+ show = show_without_test
+ return show
+ end
+ end
+ end
+end
+```
+# モジュールの読み込み
+作成したモジュールをinit.rbで読み込みます。
+
+```rb:init.rb
+Rails.configuration.to_prepare do
+ require_dependency 'issues_controller'
+
+ # patchモジュールの読み込み
+ unless IssuesController.included_modules.include? Sample::IssuesControllerPatch
+ IssuesController.send(:include, Sample::IssuesControllerPatch)
+ end
+end
+```
+
+これでチケットの参照画面にアクセスした際、チケットに紐づいたテストデータがあればそれがロードされ、なければ新規作成されるようになりました。
+
+# controllerの作成
+次にテストデータを更新する際のcontrollerを作成します。
+
+```bash:
+bundle exec rails g redmine_plugin_controller sample tests
+```
+
+```rb:app/controllers/tests_controller.rb
+class TestsController < ApplicationController
+ unloadable
+
+ def update
+ test = Test.find_by(issue_id: params[:issue_id].to_i)
+
+ column = "content"
+ value = params[:value]
+
+ if params[:pk].to_i == 2
+ column = "result"
+ value = value.to_i
+ end
+
+ if test.update(column => value)
+ render :nothing => true, :status => 200
+ else
+ render :nothing => true, :status => 404
+ end
+ end
+end
+```
+
+```rb:config/routes.rb
+Rails.application.routes.draw do
+ resources :issues do
+ post "tests/:id" => "tests#update"
+ end
+end
+```
+
+# viewの編集
+最後に前回作成したviewを、テストデータの読込/更新に対応するよう修正します。
+
+```html+erb:app/views/hooks/sample/_view_issues_show_description_bottom.html.erb
+<hr>
+<p><strong>Easy Test</strong></p>
+<table id="easy-test">
+ <tr>
+ <td>
+ <p>Content</p>
+ <a href="#" id="test-content"><% if @test.content == "" %>Empty<% else %><%= @test.content %><% end %></a>
+ </td>
+ <td>
+ <p>Result</p>
+ <a href="#" id="test-result">
+ <% if @test.result == 0 %>-<% elsif @test.result == 1 %>OK<% else %>NG<% end %>
+ </a>
+ </td>
+ </tr>
+</table>
+<input id="test-id" type="hidden" value="<%= @test.id %>">
+<link href="//cdnjs.cloudflare.com/ajax/libs/x-editable/1.5.0/jquery-editable/css/jquery-editable.css" rel="stylesheet"/>
+<script src="//cdnjs.cloudflare.com/ajax/libs/x-editable/1.5.0/jquery-editable/js/jquery-editable-poshytip.min.js"></script>
+<style type="text/css">
+table#easy-test {
+ width: 100%;
+}
+table#easy-test tr td:first-child {
+ width: 66%;
+}
+table#easy-test tr td:last-child {
+ width: 34%;
+ vertical-align: top;
+}
+div.editable-input textarea {
+ width: 500px;
+}
+div.editable-input select {
+ width: 100px;
+}
+</style>
+<script>
+$(function() {
+ $.fn.editable.defaults.url = window.location.href + '/tests/' + $("#test-id").val();
+ $.fn.editable.defaults.mode = 'inline';
+ $.fn.editable.defaults.showbuttons = 'bottom';
+
+ $('#test-content').editable({
+ type: 'textarea',
+ pk: 1
+ });
+ $('#test-result').editable({
+ type: 'select',
+ pk: 2,
+ source: [
+ { value: 0, text: '-' },
+ { value: 1, text: 'OK' },
+ { value: 2, text: 'NG' }
+ ]
+ });
+});
+</script>
+```
+
+以上で完成です!
+第2,3回全体のソースはGitHubの[リポジトリ](https://github.com/saitoxu/HookTest)に置いていますので、よろしければ参考にしてください。
+
+# 終わりに
+駆け足でRedmineのプラグイン開発方法について紹介しましたが、
+Railsのコールバックを利用する方法等、まだまだ紹介できていないことがあります。
+ぜひご自分で調べて、実際に使ってみてください!
+
+# 参考
+
+- [Plugin Internals - Redmine](http://www.redmine.org/projects/redmine/wiki/Plugin_Internals#Wrapping-an-existing-method)
+- [» Rails: alias_method_chain: 既存の処理を修正する常套手段 TECHSCORE BLOG](http://www.techscore.com/blog/2013/02/27/rails-alias_method_chain-%E6%97%A2%E5%AD%98%E3%81%AE%E5%87%A6%E7%90%86%E3%82%92%E4%BF%AE%E6%AD%A3%E3%81%99%E3%82%8B%E5%B8%B8%E5%A5%97%E6%89%8B%E6%AE%B5/)