ほげほげ

ようやく(仮)が取れたらしい。他愛もないことを書いてみるのです。

先日のRedmine移行後、開けないチケットがあるの件

先日のRedmineのデータ移行を済ませてホッとしたのもつかの間、とある過去プロジェクトのチケットを開くと500 Internal Errorが発生する現象に遭遇。

production.logを見ると

Completed 500 Internal Server Error in 93.6ms

ActionView::Template::Error (undefined method `<' for nil:NilClass):
    15:     </tr>
    16:   </thead>
    17:   <% previous_group = false %>
    18:   <tbody>
    19:   <% issue_list(issues) do |issue, level| -%>
    20:   <% if @query.grouped? && (group = @query.group_by_column.value(issue)) != previous_group %>
    21:     <% reset_cycle %>
  app/helpers/issues_helper.rb:26:in `block in issue_list'
  app/helpers/issues_helper.rb:25:in `each'
  app/helpers/issues_helper.rb:25:in `issue_list'
  app/views/issues/_list.html.erb:18:in `block in _app_views_issues__list_html_erb___813387378_46902852'
  app/views/issues/_list.html.erb:1:in `_app_views_issues__list_html_erb___813387378_46902852'
  app/views/issues/index.html.erb:63:in `_app_views_issues_index_html_erb__475153416_46074096'
  app/controllers/issues_controller.rb:87:in `block (2 levels) in index'
  app/controllers/issues_controller.rb:86:in `index'

と言ったエラーがでていた。不等号でnilとなんかを比較しているのが問題、そこまでは読めたがrubyの中身はさっぱり。

ただエラーの出るチケットと出ないチケットがあるようで、そこを糸口になんかわからないものかと調査開始。
まずチケットのデータ構造を確認。

移行元のデータ構造

+------------------+--------------+------+-----+---------+----------------+
| Field            | Type         | Null | Key | Default | Extra          |
+------------------+--------------+------+-----+---------+----------------+
| id               | int(11)      | NO   | PRI | NULL    | auto_increment | 
| tracker_id       | int(11)      | NO   | MUL | 0       |                | 
| project_id       | int(11)      | NO   | MUL | 0       |                | 
| subject          | varchar(255) | NO   |     |         |                | 
| description      | text         | YES  |     | NULL    |                | 
| due_date         | date         | YES  |     | NULL    |                | 
| category_id      | int(11)      | YES  | MUL | NULL    |                | 
| status_id        | int(11)      | NO   | MUL | 0       |                | 
| assigned_to_id   | int(11)      | YES  | MUL | NULL    |                | 
| priority_id      | int(11)      | NO   | MUL | 0       |                | 
| fixed_version_id | int(11)      | YES  | MUL | NULL    |                | 
| author_id        | int(11)      | NO   | MUL | 0       |                | 
| lock_version     | int(11)      | NO   |     | 0       |                | 
| created_on       | datetime     | YES  | MUL | NULL    |                | 
| updated_on       | datetime     | YES  |     | NULL    |                | 
| start_date       | date         | YES  |     | NULL    |                | 
| done_ratio       | int(11)      | NO   |     | 0       |                | 
| estimated_hours  | float        | YES  |     | NULL    |                | 
| parent_id        | int(11)      | YES  |     | NULL    |                | 
| root_id          | int(11)      | YES  | MUL | NULL    |                | 
| lft              | int(11)      | YES  |     | NULL    |                | 
| rgt              | int(11)      | YES  |     | NULL    |                | 
| is_private       | tinyint(1)   | NO   |     | 0       |                | 
+------------------+--------------+------+-----+---------+----------------+

移行先のデータ構造

mysql> desc issues;
+------------------+--------------+------+-----+---------+----------------+
| Field            | Type         | Null | Key | Default | Extra          |
+------------------+--------------+------+-----+---------+----------------+
| id               | int(11)      | NO   | PRI | NULL    | auto_increment |
| tracker_id       | int(11)      | NO   | MUL | NULL    |                |
| project_id       | int(11)      | NO   | MUL | NULL    |                |
| subject          | varchar(255) | NO   |     |         |                |
| description      | text         | YES  |     | NULL    |                |
| due_date         | date         | YES  |     | NULL    |                |
| category_id      | int(11)      | YES  | MUL | NULL    |                |
| status_id        | int(11)      | NO   | MUL | NULL    |                |
| assigned_to_id   | int(11)      | YES  | MUL | NULL    |                |
| priority_id      | int(11)      | NO   | MUL | NULL    |                |
| fixed_version_id | int(11)      | YES  | MUL | NULL    |                |
| author_id        | int(11)      | NO   | MUL | NULL    |                |
| lock_version     | int(11)      | NO   |     | 0       |                |
| created_on       | datetime     | YES  | MUL | NULL    |                |
| updated_on       | datetime     | YES  |     | NULL    |                |
| start_date       | date         | YES  |     | NULL    |                |
| done_ratio       | int(11)      | NO   |     | 0       |                |
| estimated_hours  | float        | YES  |     | NULL    |                |
| parent_id        | int(11)      | YES  |     | NULL    |                |
| root_id          | int(11)      | YES  | MUL | NULL    |                |
| lft              | int(11)      | YES  |     | NULL    |                |
| rgt              | int(11)      | YES  |     | NULL    |                |
| is_private       | tinyint(1)   | NO   |     | 0       |                |
| closed_on        | datetime     | YES  |     | NULL    |                |
+------------------+--------------+------+-----+---------+----------------+

構造自体は移行元とほとんど変わりがない。(closed_onというFieldが追加されていた程度)

そこで全レコードを眺めてみる。

(Bitnamini付属していたphpMyAdminにてbitnamiアカウントでログイン)
とあるチケット番号以降のデータのroot_id,lft,rgtが共にNULLとなっていた。(原因は不明)

正しく表示されるデータには
root_id=idと同値
lft=1
rgt=2
が格納されていたが、このNULLとなっているチケットがクエリーに引っかかるとInternalErrorが発生してしまうようだった。

(これらはチケットの親子関係をもつ場合に必要となる値のようだ)

移行元のデータ自体がそのようになっていた(ただそちらはエラーが出ずにチケットが表示されていた)ので、どこかの仕様変更かなにか紆余曲折があって表示できなくなっているのではないか、と想像。
(Redmineの歴史を調べる気にはならず…)


とりあえず問題になるレコードはわかったということで以下のupdate文を流す。

update issues 
set root_id = id, lft = 1, rgt = 2
where root_id is NULL and lft is NULL and rgt is NULL; 

全てのレコードがNULLじゃなくなったのを確認し、commit。


無事Redmineチケットのクエリができるようになった!

(参考にしたサイト)
このあたりは問題がでる部分らしい。(今回とは別事象であるが、チケットの親子関係が崩れた場合なども発生する)
http://dqn.sakusakutto.jp/2013/09/redmine_issue_parent_id_root_id_lft_rgt.html
http://www.redmine.org/boards/2/topics/23247