Redmineのプロジェクトごとに「新しいチケット」画面を変える方法

前置き

プロジェクトAとプロジェクトBで、「新しいチケット」画面を変えたいと思いませんか?
仕事でプロジェクトごとに入力項目を変えることがあったので、今回はその方法をご紹介しようと思います。

デモ環境

Redmine 2.4.1.stable

やってみること

  • プロジェクトA
    • 画面に「Project A」と表示してみる
  • プロジェクトB
    • 画面に「Project B」と表示してみる
    • 「説明」を非表示にする

前準備

新しいプロジェクトとして、「プロジェクトA」と「プロジェクトB」を作っておきます。

修正内容

1.ファイルをコピーしてリネーム

下記3ファイルをコピーしてリネームし、プロジェクトA用のファイルとプロジェクトB用のファイルを作ります。

/app/view/issue/_form.html.erb
/app/view/issue/_attributes.html.erb
/app/view/issue/_form_custom_fields.html

プロジェクトA用のファイル

  • /app/view/issue/_formA.html.erb
  • /app/view/issue/_attributesA.html.erb
  • /app/view/issue/_form_custom_fieldsA.html

プロジェクトB用のファイル

  • /app/view/issue/_formB.html.erb
  • /app/view/issue/_attributesB.html.erb
  • /app/view/issue/_form_custom_fieldsB.html

2.上記のファイルをそれぞれ修正

_formA.html.erb

<%= labelled_fields_for :issue, @issue do |f| %>
<%= call_hook(:view_issues_form_details_top, { :issue => @issue, :form => f }) %>
+ <p><strong>Project A</strong></p>
<% if @issue.safe_attribute? 'is_private' %>
<p style="display:none; float:right; margin-right:1em;">
  <%= f.check_box :is_private, :no_label => true %><label class="inline" for="issue_is_private" id="issue_is_private_label"><%= l(:field_is_private) %></label>
</p>
<% end %>

<% if @issue.safe_attribute? 'project_id' %>
<p><%= f.select :project_id, project_tree_options_for_select(@issue.allowed_target_projects, :selected => @issue.project), {:required => true},
                :onchange => "updateIssueFrom('#{escape_javascript project_issue_form_path(@project, :id => @issue, :format => 'js')}')" %></p>
<% end %>

<% if @issue.safe_attribute? 'tracker_id' %>
<p><%= f.select :tracker_id, @issue.project.trackers.collect {|t| [t.name, t.id]}, {:required => true},
                :onchange => "updateIssueFrom('#{escape_javascript project_issue_form_path(@project, :id => @issue, :format => 'js')}')" %></p>
<% end %>

<% if @issue.safe_attribute? 'subject' %>
<p><%= f.text_field :subject, :size => 80, :maxlength => 255, :required => true %></p>
<% end %>

<% if @issue.safe_attribute? 'description' %>
<p>
  <%= f.label_for_field :description, :required => @issue.required_attribute?('description') %>
  <%= link_to_function image_tag('edit.png'), '$(this).hide(); $("#issue_description_and_toolbar").show()' unless @issue.new_record? %>
  <%= content_tag 'span', :id => "issue_description_and_toolbar", :style => (@issue.new_record? ? nil : 'display:none') do %>
    <%= f.text_area :description,
                   :cols => 60,
                   :rows => (@issue.description.blank? ? 10 : [[10, @issue.description.length / 50].max, 100].min),
                   :accesskey => accesskey(:edit),
                   :class => 'wiki-edit',
                   :no_label => true %>
  <% end %>
</p>
<%= wikitoolbar_for 'issue_description' %>
<% end %>

<div id="attributes" class="attributes">
-  <%= render :partial => 'issues/attributes' %>
+  <%= render :partial => 'issues/attributesA' %>
</div>

<%= call_hook(:view_issues_form_details_bottom, { :issue => @issue, :form => f }) %>
<% end %>

_attributesA.html.erb

- <%= render :partial => 'issues/form_custom_fields' %>
+ <%= render :partial => 'issues/form_custom_fieldsA' %>

※ /app/view/issue/_form_custom_fieldsA.html.erbは特に修正しません。

同様に、
_formB.html.erb
_attributesB.html.erb
も修正していきます。

_formB.html.erb

<%= labelled_fields_for :issue, @issue do |f| %>
<%= call_hook(:view_issues_form_details_top, { :issue => @issue, :form => f }) %>
+ <p><strong>Project B</strong></p>
<% if @issue.safe_attribute? 'is_private' %>
<p style="display:none; float:right; margin-right:1em;">
  <%= f.check_box :is_private, :no_label => true %><label class="inline" for="issue_is_private" id="issue_is_private_label"><%= l(:field_is_private) %></label>
</p>
<% end %>

<% if @issue.safe_attribute? 'project_id' %>
<p><%= f.select :project_id, project_tree_options_for_select(@issue.allowed_target_projects, :selected => @issue.project), {:required => true},
                :onchange => "updateIssueFrom('#{escape_javascript project_issue_form_path(@project, :id => @issue, :format => 'js')}')" %></p>
<% end %>

<% if @issue.safe_attribute? 'tracker_id' %>
<p><%= f.select :tracker_id, @issue.project.trackers.collect {|t| [t.name, t.id]}, {:required => true},
                :onchange => "updateIssueFrom('#{escape_javascript project_issue_form_path(@project, :id => @issue, :format => 'js')}')" %></p>
<% end %>

<% if @issue.safe_attribute? 'subject' %>
<p><%= f.text_field :subject, :size => 80, :maxlength => 255, :required => true %></p>
<% end %>

<% if @issue.safe_attribute? 'description' %>
- <p>
+ <p style="display:none;>
  <%= f.label_for_field :description, :required => @issue.required_attribute?('description') %>
  <%= link_to_function image_tag('edit.png'), '$(this).hide(); $("#issue_description_and_toolbar").show()' unless @issue.new_record? %>
  <%= content_tag 'span', :id => "issue_description_and_toolbar", :style => (@issue.new_record? ? nil : 'display:none') do %>
    <%= f.text_area :description,
                   :cols => 60,
                   :rows => (@issue.description.blank? ? 10 : [[10, @issue.description.length / 50].max, 100].min),
                   :accesskey => accesskey(:edit),
                   :class => 'wiki-edit',
                   :no_label => true %>
  <% end %>
</p>
<%= wikitoolbar_for 'issue_description' %>
<% end %>

<div id="attributes" class="attributes">
-  <%= render :partial => 'issues/attributes' %>
+  <%= render :partial => 'issues/attributesB' %>
</div>

<%= call_hook(:view_issues_form_details_bottom, { :issue => @issue, :form => f }) %>
<% end %>

_attributesB.html.erb

- <%= render :partial => 'issues/form_custom_fields' %>
+ <%= render :partial => 'issues/form_custom_fieldsB' %>

3./app/view/issue/new.html.erbに条件分岐を差し込む

  <div class="box tabular">
-    <div id="all_attributes">
-    <%= render :partial => 'issues/form', :locals => {:f => f} %>
-    </div>
+    <div id="all_attributes">
+        <% if @project.to_s == "プロジェクトA" then %>
+            <%= render :partial => 'issues/formA', :locals => {:f => f} %>
+        <% elsif @project.to_s == "プロジェクトB" then %>
+            <%= render :partial => 'issues/formB', :locals => {:f => f} %>
+        <% else %>
+            <%= render :partial => 'issues/form', :locals => {:f => f} %>
+        <% end %>
+    </div>

※注意

  • 「プロジェクト名」で引っかけて分岐しているので、プロジェクト名を変えたら、上記new.html.erbのif文部分も変更してください
  • プラグインで「redmine boards watchers」を使っている場合は、”/plugins/redmine_boards_watchers/app/views/issues/”にも「new.html.erb」がいますので、上記と同様に修正してください。修正しないとエラーになります。

4.Redmineを再起動

さてと、ちゃんと変わってるかな。

結果

おぉ~、変わってる変わってる。

プロジェクトAの新しいチケット画面
プロジェクトAの新しいチケット画面
プロジェクトBの新しいチケット画面
プロジェクトBの新しいチケット画面

というわけで、この記事が僕と同じように「手さぐりでRedmineをカスタマイズしながら使っている、プレイングマネージャー的な雑用係 兼 ディレクター 兼 プロマネ」の手助けになれば幸いです。
otsukare-tion.comはがんばる社畜を応援しています。

Amazon

Redmineによるタスクマネジメント実践技法
Redmine -もっと手軽にプロジェクト管理!
入門Redmine 第3版

コメントを残す