RedmineのWikiでSQLを発行した結果を利用するマクロを作成する(2)

# はじめに

以前、RedmineのWikiでSQLを直接叩いて結果を取得し、出力するマクロを作りました。
* [RedmineのWikiでSQLを発行した結果を利用するマクロを作成する](https://qiita.com/akasa_y/items/820ce2e69d2110f81e94)

上記方法では、生SQLを使用していたためデータベースによって結果が変わってしまうことに気が付きました。近々また調べようと思うと書いたけれど、そんな日は必要に迫られるまで来るはずもなく、今回Redmine 5.1にアップデートするためRedmineのWikiでデータベースの値を取得し表にするマクロを作り直しました。

# 自作マクロの作成

Redmineは Ruby on Rails を採用しているので、Active Recordを使ってデータベースから情報を取るようにする。以下のように所属するwikiのプロジェクトのバージョンごとにトラッカーと残チケット数を表示するマクロを作る。（バージョンをクリックするとバージョンの説明画面、残チケットの数をクリックすると該当するチケットがフィルタされた画面に飛ぶようリンクを作る。）

<table>
  <thead>
    <tr><th>バージョン</th><th>トラッカー</th><th>期日</th><th>残チケット</th></tr>
  </thead>
  <tbody>
    <tr><td><a class="version" href="./">αリリース</a></td><td>バグ</td><td>2023-11-10</td><td><a href="./">1</a></td></tr>
    <tr><td><a class="version" href="./">αリリース</a></td><td>機能</td><td>2023-11-10</td><td><a href="./">2</a></td></tr>
    <tr><td><a class="version" href="./">βリリース</a></td><td>機能</td><td>2023-11-24</td><td><a href="./">1</a></td></tr>
  </tbody>
</table>

結局、色々試してみたところ以下のコードで意図した表を生成できるようになった。

```ruby:init.rb
  Redmine::WikiFormatting::Macros.register do
    desc "Get current project version and status"
    macro :get_version_status2 do |obj, args|
      str = "<table>"
      str << "<thead><tr><th>バージョン</th><th>トラッカー</th><th>期日</th><th>残チケット</th></tr></thead>"
      str << "<tbody>"
      versions = @project.shared_versions.to_a
      versions.each do |version|
        results = Issue.joins(:status).joins(:tracker).where(:project_id => @project.id, :fixed_version_id => version.id, status: { is_closed: false }).group("trackers.name").count
        results.each {|key, value|
          tid = Tracker.find_by_name(key).id
          str << "<tr><td>" << link_to(version.name,{:controller => 'versions', :action => 'show', :id => version.id}, :class => 'version') << "</td><td>" << key << "</td><td>" << version.effective_date.to_s << "</td><td>" << link_to(value.to_s, project_issues_path(@project, :fixed_version_id => version.id, :set_filter => '1', :status_id => 'o', :tracker_id => tid.to_s)) << "</td></tr>"
        }
      end
      str << "</tbody></table>"
      return str.html_safe
    end
  end
```

子プロジェクトに関しても一覧化したい場合
```ruby:init.rb
  Redmine::WikiFormatting::Macros.register do
    desc "Get current project version and status"
    macro :get_version_status3 do |obj, args|
      str = "<table>"
      str << "<thead><tr><th>プロジェクト</th><th>バージョン</th><th>トラッカー</th><th>期日</th><th>残チケット</th></tr></thead>"
      str << "<tbody>"
      1.upto(Project.count) do |pid|
        pj = Project.find(pid)
        if pj.parent_id == @project.id || pj.id == @project.id then
          versions = pj.shared_versions.to_a
          versions.each do |version|
            results = Issue.joins(:status).joins(:tracker).where(:project_id => pid, :fixed_version_id => version.id, status: { is_closed: false }).group("trackers.name").count
            results.each {|key, value|
              tid = Tracker.find_by_name(key).id
              str << "<tr><td>" << pj.name.to_s << "</td><td>" << link_to(version.name,{:controller => 'versions', :action => 'show', :id => version.id}, :class => 'version') << "</td><td>" << key << "</td><td>" << version.effective_date.to_s << "</td><td>" << link_to(value.to_s, project_issues_path(pj, :fixed_version_id => version.id, :set_filter => '1', :status_id => 'o', :tracker_id => tid.to_s)) << "</td></tr>"
            }
          end
        end
      end
      str << "</tbody></table>"
      return str.html_safe
    end
  end
```
きっともっと良い方法があると思うのですが、忘れてしまうので恥を忍んで残しておこうと思います。主にRedmine内のコードを参考にして作成。

# 動作確認環境

* Redmine 5.1.0.stable.22412
* Ruby version 3.1.4-p223 (2023-03-30) [x86_64-linux]
* Rails version 6.1.7.6
* Database adapter PostgreSQL

# 参考文献

以下のページを参考にさせて頂きました。ありがとうございました。

* [ActiveRecordにおけるGROUP BYの使い方](https://qiita.com/yuyasat/items/e26bcf0eb2c89c63db9d)