Railsでストアドを呼び出して結果を取得する方法
SQL Serverの場合
ストアドプロシージャを用意する。
INの文字列をテーブル登録して、OUT='okaeshi'、888を返す訳分からんプロシージャ。
CREATE PROCEDURE TEST_PROC @Param1 varchar(10) , @Param2 varchar(100) OUTPUT AS BEGIN INSERT INTO TESTS(COLUMN1) values(@Param1) SELECT @Param2 = 'okaeshi' RETURN 888 END
SQL Serverのストアド用モデルを用意する。
class SqlServerStoredProcedure < ActiveRecord::Base def self.proc_exec(sql) find_by_sql(sql) end establish_connection "sqlsvr" end
呼び出し方
sql = "declare @rtn int" sql += ",@Param2 varchar(100);" sql += "exec @rtn = test_proc" sql += " @Param1 = N'" + "ACBDEFG" + "'" sql += ",@Param2 = @Param2 output;" sql += "select 'rtns' = @rtn" sql += ",Param2 = @Param2;" @rtns = SqlServerStoredProcedure.proc_exec(sql)
結果をViewに表示
結果はHashの配列で返されるので・・・
[{"rtns"=>888, "Param2"=>"okaeshi"}]
View側は次のように取り出す。
<p><%=h @rtns.first["rtns"] %></p> <p><%=h @rtns.first["Param2"] %></p>
呼び出す時にSQLを作る必要があるのだが、もっとすっきりした方法がいいな・・・
Oracleの場合
参考:
http://mikebradford.org/2008/3/11/calling-an-oracle-stored-procedure-in-rails
ActiveRecord, Oracle and stored procedures | Software bits and pieces
ストアドプロシージャを用意する。
INの文字列をOUTで返すプロシージャ。
create or replace procedure testproc( instr in char , outstr out char ) as begin outstr := instr; end; /
Oracleのストアド用モデルを用意する。
class OraSp < ActiveRecord::Base def self.proc_exec conn = connection.raw_connection sql = "DECLARE outstr char(100); BEGIN testproc(:instr, outstr); :outstr := outstr; END;" cursor = conn.parse(sql) cursor.bind_param(":instr", "AAAAA") cursor.bind_param(":outstr", nil, String, 100) cursor.exec outstr = cursor[":outstr"] cursor.close outstr end establish_connection "oracle" end
呼び出し方
@outstr = OraSp.proc_exec
結果をViewに表示
<p><%=h @outstr %></p>
bind_paramで苦労した・・・
OUTパラメータは、プロシージャの引数の位置に設定できないみたい。
ダメだった例:
sql = "BEGIN testproc(:instr, ★:outstr★); END;"
OKだった例:
sql = "DECLARE outstr char(100); BEGIN testproc(:instr, outstr); ★:outstr★ := outstr; END;"
Redmine1.0.0にアップデート
待ちに待ったRedmine1.0.0が7/18にリリースされた。
早速アップデートしてみる。(trunk -> 1.0.0)
Redmineのバックアップ
- Redmine本体のバックアップ
cd /var cp -rp redmine redmine_100719
- データベース(MySQL)のバックアップ
mysqldump -c redmine | gzip >/home/redmine_100719.sql.gz
trunkから1.0.0へアップデート(切り替え)
- 現状のリポジトリを確認
cd /var/redmine svn info ----------------------------------------------- パス: . URL: http://redmine.rubyforge.org/svn/trunk リポジトリのルート: http://redmine.rubyforge.org/svn リポジトリ UUID: e93f8b46-1217-0410-a6f0-8f06a7374b81 リビジョン: 3768 ノード種別: ディレクトリ 準備中の処理: 特になし 最終変更者: edavis10 最終変更リビジョン: 3768 最終変更日時: 2010-06-10 07:01:21 +0900 (木, 10 6月 2010)
- リポジトリ切り替え
cd /var/redmine svn switch http://redmine.rubyforge.org/svn/branches/1.0-stable
- データベースのマイグレーション
cd /var/redmine rake db:migrate RAILS_ENV="production"
- キャッシュとセッションの消去
cd /var/redmine rake tmp:cache:clear rake tmp:sessions:clear
- リスタート
cd /var/redmine touch tmp/restart.txt
感想
trunkから1.0.0への切り替えなので、当然ながら特に変化はなかったw
(0.9からは沢山の機能が追加されている。)
個人的にはsubtaskingが正式に採用されたことが一番大きい。
まぁまだリリース候補版なんで気長に付き合おう。
兎に角、1.0.0をリリース出来たことに”おめでとう”と”ありがとう”の意をお伝えしたい。
Jean-Philippe Langさん初め開発者の方々、"Congratulations" and "Thank you".
1.0.0のリリース情報
RedmineのPDF文字化けと日付表示と統計表示
PDFの文字化けの対応
完璧ではないらしいが、やってみる。
- 参考URL
PDFおよびCSVの文字化けを回避する — Redmine.JP
Google グループ
Redmineの文字化けとか勝手にまとめ: これ本番ですか?
徒然さめざめ Redmine Hack! - pdfの文字化け fix編 -
http://www.maruhisa.org/2009/07/redmine_pdf_problem/
徒然さめざめ 続・何回目? Redmine pdf日本語化hack
- config/locales/ja.yml
- general_csv_encoding: CP932 - general_pdf_encoding: CP932 + general_csv_encoding: SJIS + general_pdf_encoding: SJIS
pdf.rbのMultiCellの引数(文字列)にひたすら.tosjisをかます。
- lib/redmine/export/pdf.rb
- pdf.MultiCell(155,5, (show_value custom_value),"R") + pdf.MultiCell(155,5, (show_value.tosjis custom_value.tosjis),"R") - pdf.MultiCell(155,5, @issue.description,"BR") + pdf.MultiCell(155,5, @issue.description.tosjis,"BR") - pdf.MultiCell(190,5, changeset.comments) + pdf.MultiCell(190,5, changeset.comments.tosjis) - pdf.MultiCell(190,5, journal.notes) + pdf.MultiCell(190,5, journal.notes.tosjis)
履歴に何か書くと次のエラーを吐いて落ちる・・・
Processing IssuesController#show to pdf (for 192.168.24.83 at 2010-07-09 01:10:36) [GET] Parameters: {"format"=>"pdf", "action"=>"show", "id"=>"3", "controller"=>"issues"} TypeError (nil can't be coerced into Fixnum): lib/redmine/export/pdf.rb:294:in `issue_to_pdf' lib/redmine/export/pdf.rb:283:in `each' lib/redmine/export/pdf.rb:283:in `issue_to_pdf' app/controllers/issues_controller.rb:128:in `show' app/controllers/issues_controller.rb:123:in `show' passenger (2.2.11) lib/phusion_passenger/rack/request_handler.rb:92:in `process_request' passenger (2.2.11) lib/phusion_passenger/abstract_request_handler.rb:207:in `main_loop' passenger (2.2.11) lib/phusion_passenger/railz/application_spawner.rb:418:in `start_request_handler' passenger (2.2.11) lib/phusion_passenger/railz/application_spawner.rb:358:in `handle_spawn_application' passenger (2.2.11) lib/phusion_passenger/utils.rb:184:in `safe_fork' passenger (2.2.11) lib/phusion_passenger/railz/application_spawner.rb:354:in `handle_spawn_application' passenger (2.2.11) lib/phusion_passenger/abstract_server.rb:352:in `__send__' passenger (2.2.11) lib/phusion_passenger/abstract_server.rb:352:in `main_loop' passenger (2.2.11) lib/phusion_passenger/abstract_server.rb:196:in `start_synchronously' passenger (2.2.11) lib/phusion_passenger/abstract_server.rb:163:in `start' passenger (2.2.11) lib/phusion_passenger/railz/application_spawner.rb:213:in `start' passenger (2.2.11) lib/phusion_passenger/spawn_manager.rb:262:in `spawn_rails_application' passenger (2.2.11) lib/phusion_passenger/abstract_server_collection.rb:126:in `lookup_or_add' passenger (2.2.11) lib/phusion_passenger/spawn_manager.rb:256:in `spawn_rails_application' passenger (2.2.11) lib/phusion_passenger/abstract_server_collection.rb:80:in `synchronize' passenger (2.2.11) lib/phusion_passenger/abstract_server_collection.rb:79:in `synchronize' passenger (2.2.11) lib/phusion_passenger/spawn_manager.rb:255:in `spawn_rails_application' passenger (2.2.11) lib/phusion_passenger/spawn_manager.rb:154:in `spawn_application' passenger (2.2.11) lib/phusion_passenger/spawn_manager.rb:287:in `handle_spawn_application' passenger (2.2.11) lib/phusion_passenger/abstract_server.rb:352:in `__send__' passenger (2.2.11) lib/phusion_passenger/abstract_server.rb:352:in `main_loop' passenger (2.2.11) lib/phusion_passenger/abstract_server.rb:196:in `start_synchronously' Rendering /var/redmine/public/500.html (500 Internal Server Error)
とりあえず履歴と関連するリビジョンは印字してもらう必要ないので、その印字処理を削除する。
# if issue.changesets.any? && User.current.allowed_to?(:view_changesets, issue.project) # pdf.SetFontStyle('B',9) # pdf.Cell(190,5, l(:label_associated_revisions), "B") # pdf.Ln # for changeset in issue.changesets # pdf.SetFontStyle('B',8) # pdf.Cell(190,5, format_time(changeset.committed_on) + " - " + changeset.author.to_s) # pdf.Ln # unless changeset.comments.blank? # pdf.SetFontStyle('',8) # pdf.MultiCell(190,5, changeset.comments.tosjis) # end # pdf.Ln # end # end # pdf.SetFontStyle('B',9) # pdf.Cell(190,5, l(:label_history), "B") # pdf.Ln # for journal in issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC") # pdf.SetFontStyle('B',8) # pdf.Cell(190,5, format_time(journal.created_on) + " - " + journal.user.name) # pdf.Ln # pdf.SetFontStyle('I',8) # for detail in journal.details # pdf.Cell(190,5, "- " + show_detail(detail, true)) # pdf.Ln # end # unless journal.notes.blank? # pdf.SetFontStyle('',8) # pdf.MultiCell(190,5, journal.notes.tosjis) # end # pdf.Ln # end
ブラウザの機能で印字する場合は、次のツールで余計な部分を取り除くことにしよう。
https://addons.mozilla.org/ja/firefox/addon/193270/
ガントチャートに日付表示
- 参考URL
http://labo-ss.net/blog/itroom/item_46.html
プロジェクト管理ツールRedMineのガントチャートカスタマイズ - + YOSHIKI & Violet UK FAN SITE -Blind Tears- 管理人の日記 +
- app/views/gantts/show.html.erb(r3756)
44 headers_height = header_heigth 45 show_weeks = false 46 show_days = false 47 show_day_num = false #★追加★ 48 49 if @gantt.zoom >1 50 show_weeks = true 51 headers_height = 2*header_heigth 52 if @gantt.zoom > 2 53 show_days = true 54 headers_height = 3*header_heigth 55 if @gantt.zoom > 3 #★追加★ 56 show_day_num = true #★追加★ 57 headers_height = 4*header_heigth #★追加★ 58 end #★追加★ 59 end 60 end 150 <!-- ★追加★ start --> 151 <% 152 # 153 # Days headers Num 154 # 155 if show_day_num 156 left = 0 157 height = g_height + header_heigth * 2 - 1 158 wday = @gantt.date_from.cwday 159 day_num = @gantt.date_from 160 (@gantt.date_to - @gantt.date_from + 1).to_i.times do 161 width = zoom - 1 162 %> 163 <div style="left:<%= left %>px;top:37px;width:<%= width %>px;height:<%= height %>px;font-size:0.7em;<%= "background:#f1f1f1;" if wday > 5 %><%= "color:blue;" if wday == 6 %> <%= "color:red;" if wday == 7 % >" class="gantt_hdr"> 164 <%= day_num.day %> 165 </div> 166 <% 167 left = left + width+1 168 day_num = day_num + 1 169 wday = wday + 1 170 wday = 1 if wday > 7 171 end 172 end %> 173 <!-- ★追加★ end --> 175 <% 176 # 177 # Days headers 178 # 179 if show_days 180 left = 0 181 height = g_height + header_heigth - 1 182 top = (show_day_num ? 55 : 37) #★追加★ 183 wday = @gantt.date_from.cwday 184 (@gantt.date_to - @gantt.date_from + 1).to_i.times do 185 width = zoom - 1 186 %> 187 <!-- <div style="left:<%= left %>px;top:37px;width:<%= width %>px;height:<%= height %>px;font-size:0.7em;<%= "background:#f1f1f1;" if wday > 5 %>" class="gantt_hdr"> --> 188 <div style="left:<%= left %>px;top:<%= top %>px;width:<%= width %>px;height:<%= height %>px;font-size:0.7em;<%= "background:#f1f1f1;" if wday > 5 %><%= "color:blue;" if wday == 6 %><%= "color:red;" if wday == 7 %>" class="gantt_hdr"> <!-- ★変更★ --> 189 <%= day_name(wday).first %> 190 </div> 191 <% 192 left = left + width+1 193 wday = wday + 1 194 wday = 1 if wday > 7 195 end 196 end %>
最大の大きさの時(拡大+4)に日付を表示してくれる。
なかなかいい感じ。先人の方々に感謝。
統計が表示されない
ruby1.8のバグらしい。
Redmineで統計を表示する: これ本番ですか?
下記の通り修正すれば表示出きるようになった。
- /usr/lib/ruby/1.8/rexml/document.rb
186 # if transitive 187 if trans
Redmineの初回アクセスが遅い
Subversionのpre-commitフックを強化
前に”コミットに制約を設ける”と題してpre-commitのスクリプトを作成したが、不完全だったので作り直してみた。
コミットに制約を設ける(強化版)
制約内容:
- 参照用(refs)のチケット番号が指定されていて、そのチケットがRedmimeに存在すること。
- 完了用(fixes)のチケット番号が指定されていた場合は、そのチケットがRedmineに存在して、かつ、完了していないこと。
- 修正したpre-commit
#!/usr/bin/env ruby #REPOS="$1" #TXN="$2" # Make sure that the log message contains some text. #SVNLOOK=/usr/bin/svnlook #$SVNLOOK log -t "$TXN" "$REPOS" | \ # grep "[a-zA-Z0-9]" > /dev/null || exit 1 # Check that the author of this commit has the rights to perform # the commit on the files and directories being modified. #commit-access-control.pl "$REPOS" "$TXN" commit-access-control.cfg || exit 1 #---------------------------------- #デバッグ出力と標準エラー出力の関数 #---------------------------------- def dbg(format, *arg) f = open("/tmp/pre-commit.log", "a") printf(f, format, *arg) f.close printf(STDERR, format, *arg) end #-------------------------------- #指定チケットの進捗率を求める関数 #-------------------------------- def getTicketRatio(ticketNo) redmine = <<-`__REDMINE__` #{MYSQL} -s -u root redmine <<__SQL__ select issues.done_ratio from issues where issues.id = #{ticketNo} ; __SQL__ __REDMINE__ #数値でない場合は nil を返す if redmine.chomp.strip =~ /^[0-9]+$/ then return redmine.chomp.strip.to_i else return nil end end #引数セット REPOS = ARGV[0] TXN = ARGV[1] #外部プログラムのパスを設定 SVNLOOK = "/usr/bin/svnlook" MYSQL = "/usr/bin/mysql" #デバッグ dbg("--- %s ---\n", Time.now) dbg("REPOS=[%s], TXN=[%s]\n", REPOS, TXN) #チェック用変数初期化 refsCnt = 0 errCnt = 0 #コミットログを取得 log = `#{SVNLOOK} log -t #{TXN} #{REPOS}` log.each do |item| #ログを加工 item.chomp! #改行コードを取り除く item.strip! #前後の空白を取り除く item.downcase! #小文字に変換 item.gsub!("references", "refs") #参照用キーワードを統一 item.gsub!("IssueID", "refs") #参照用キーワードを統一 item.gsub!("closes", "fixes") #修正用キーワードを統一 #参照用チケットをチェック refs = item.scan(/refs[ ]*[#|0-9| |,]+/) refs.each do |ref| tickets = ref.scan(/#[0-9]+/) tickets.each do |ticket| #進捗率が求めれない場合はエラー if getTicketRatio(ticket.gsub("#", "")).nil? then dbg("Ticket %s is nothing.\n", ticket) errCnt += 1 else dbg("Ticket %s is validity.\n", ticket) refsCnt += 1 end end end #修正用チケットをチェック fixes = item.scan(/fixes[ ]*[#|0-9| |,]+/) fixes.each do |fix| tickets = fix.scan(/#[0-9]+/) tickets.each do |ticket| #進捗率が求めれない場合はエラー #進捗率が100%の場合はエラー if getTicketRatio(ticket.gsub("#", "")).nil? then dbg("Ticket %s is nothing.\n", ticket) errCnt += 1 elsif 100 == getTicketRatio(ticket.gsub("#", "")) then dbg("Ticket %s is complite.\n", ticket) errCnt += 1 else dbg("Ticket %s is validity.\n", ticket) end end end end #参照用チケットがない場合はエラー if 0 == refsCnt then dbg("No refs ticket.(refs #)\n") errCnt += 1 end #エラーがある場合は exit 1 で終了 if 0 < errCnt then dbg("--- NG %s ---\n", Time.now) exit 1 end # All checks passed, so allow the commit. dbg("--- OK %s ---\n", Time.now) exit 0
Redmienのリポジトリ情報の自動読み込みとバーンダウンチャート
コミット直後にリポジトリを読み込むようにする
Redmine.JP Blogの通りに設定
小技(0.9): コミットと同時にリポジトリの情報を取得する | Redmine.JP Blog
- post-commitの内容
#!/bin/sh REPOS="$1" REV="$2" #commit-email.pl "$REPOS" "$REV" commit-watchers@example.org #log-commit.py --repository "$REPOS" --revision "$REV" /usr/bin/ruby -ropen-uri -e 'open("http://localhost/redmine/sys/fetch_changesets?key=iIZbaD1eRPoW7Oy6Amue")'
バーンダウンチャートを見れるようにする(Charts pluginを入れる)
公式のWikiの通りにやってみる。
ただ、gitが必要なので先ずはそれをインストールする。
/etc/yum.repos.d/CentOS-Base.repoの末尾に以下の内容を追記する。
[dag] name=Dag RPM Repository for Redhat EL5 baseurl=http://apt.sw.be/redhat/el$releasever/en/$basearch/dag gpgcheck=1 enabled=1 gpgkey=http://dag.wieers.com/packages/RPM-GPG-KEY.dag.txt
- gitをインストール
yum install git
- OpenFlashChartをインストール
cd /var/redmine ./script/plugin install git://github.com/pullmonkey/open_flash_chart.git
- Charts pluginをインストール
cd /var/redmine git clone git://github.com/mszczytowski/redmine_charts.git vendor/plugins/redmine_charts
- おまじない
rake db:migrate_plugins RAILS_ENV=production
- Redmine再起動
cd /var/redmine touch tmp/restart.txt
- [管理]→[プロジェクト]でモジュールに"Chart"を追加する。
- [管理]→[ロールと権限]で"Chart"の権限を設定する。
- 感想
まずバーンダウンが良く分かってない。。。が、なんかかっちょいいし、見やすい。
とりあえず、開始日、期日、予定工数、作業時間をキチンと入力することで、進捗の度合いが分かるグラフを見ることができる。
作業時間の入力をキチンと運用できれば確実に使える!
以下、説明文のコピペ(こちらに倣ってredmine_chartsプラグインでバーンダウンチャートは表示可能: プログラマの思索)
- バーンダウン
- 見積、経過および残りの時間を表しています
- 進捗とバーンダウン
- 進捗とバーンダウン(残り時間)。 各バージョンにおける作成日から(実際の)完了までのデータを表しています。
- 記録時間割合
- 時間はメンバ、チケット、活動、カテゴリごとに分類およびフィルタした記録時間の合計に比例しています
- 記録時間予定
- メンバ、チケット、活動、カテゴリごとに分類およびフィルタして時間経過を表しています
- 記録時間分布
- 各チケットの見積時間と記録時間と残り時間の割合を表しています。この割合は100%以下になるべきです。見積時間のあるチケットのみ表示しています。左端に表示しているバーはこのプロジェクトの平均値を表しています。
- チケットレート
- 指定された条件・グループでのチケット数を表しています。
RedmineにおけるSubversionの認証方法
Redmineの"committer"というグループに所属するユーザだけがコミットできるようにする認証方法を考えてみた。
前に特定のプロジェクトに所属するユーザだけコミット可能とする方法を考えてみたが、こっちの方が直かな。
- /etc/httpd/conf.d/subversion.conf
<Location /svn> DAV svn SVNParentPath /home1/svnrepos <LimitExcept GET PROPFIND OPTIONS REPORT> AuthMySQLEnable On AuthMySQLSocket /var/lib/mysql/mysql.sock AuthMySQLHost localhost AuthMySQLUser redmine AuthMySQLPassword redmine AuthMySQLDB redmine AuthMySQLUserTable "users" AuthMySQLNameField "users.login" AuthMySQLUserCondition "users.id in (select groups_users.user_id from users,groups_users where users.type = 'Group' and users.lastname = 'committer' and users.id = groups_users.group_id)" AuthMySQLPasswordField "users.hashed_password" AuthMySQLPwEncryption sha1 AuthMySQLNoPasswd Off AuthType Basic AuthName "Authorization Realm" Require valid-user </LimitExcept> </Location>