発生した環境
- Bitnami Redmine Stack (Windows版) 1.4 から 3.1.1 へのアップグレード後
- 通常のIssue作成、閲覧は問題ない
- カスタムクエリだけ 500 Internal Error
原因
- production.log によるとVIEWの表示で ASCII-8BIT から UTF-8 へ変換できないとのこと。
Started GET "/redmine/projects/a/issues?query_id=1" for 192.168.XX.XX at 2015-XX-XX XX:XX:XX +0900
Processing by IssuesController#index as HTML
Parameters: {"query_id"=>"1", "project_id"=>"a"}
Current user: User (id=1)
Rendered queries/_filters.html.erb (10.0ms)
Rendered issues/index.html.erb within layouts/base (16.0ms)
Completed 500 Internal Server Error in 261ms (ActiveRecord: 101.0ms)
ActionView::Template::Error ("\xE4" from ASCII-8BIT to UTF-8):
7: $(document).ready(function(){
8: initFilters();
9: <% query.filters.each do |field, options| %>
10: addFilter("<%= field %>", <%= raw_json query.operator_for(field) %>, <%= raw_json query.values_for(field) %>);
11: <% end %>
12: });
13: <% end %>
app/helpers/application_helper.rb:1076:in `raw_json'
app/views/queries/_filters.html.erb:10:in `block (2 levels) in _app_views_queries__filters_html_erb__85224075_77320944'
app/views/queries/_filters.html.erb:9:in `each'
app/views/queries/_filters.html.erb:9:in `block in _app_views_queries__filters_html_erb__85224075_77320944'
app/views/queries/_filters.html.erb:1:in `_app_views_queries__filters_html_erb__85224075_77320944'
app/views/issues/index.html.erb:19:in `block in _app_views_issues_index_html_erb___72240600_77564676'
app/views/issues/index.html.erb:11:in `_app_views_issues_index_html_erb___72240600_77564676'
app/controllers/issues_controller.rb:77:in `block (2 levels) in index'
app/controllers/issues_controller.rb:76:in `index'
lib/redmine/sudo_mode.rb:63:in `sudo_mode'
app/helpers/application_helper.rb にある raw_json が問題を起こしている様子。
# Helper to render JSON in views
def raw_json(arg)
arg.to_json.to_s.gsub('/', '\/').html_safe
end
arg.inspect
してみるとちゃんと UTF-8 だと判定されたりASCII-8BIT (例えば"\xE4")と判定されたり混ざっていた。rubyでは「文字コードの違うものどうしを結合できない」とエラーになってしまう。
対処(とりあえず)
呼び出し元で対処するか、このraw_jsonで対応すべきか正直迷ったのですが。
来たものを片っ端からUTF-8にしてしまうことで逃げる。
# Helper to render JSON in views
def raw_json(arg)
arg = force_utf8_strings(arg) # add
arg.to_json.to_s.gsub('/', '\/').html_safe
end
ファイルの末(Private メソッドの並び)
private
# (略)
# add
def force_utf8_strings(arg)
if arg.is_a?(String)
arg.dup.force_encoding('UTF-8')
elsif arg.is_a?(Array)
arg.map do |a|
force_utf8_strings(a)
end
elsif arg.is_a?(Hash)
arg = arg.dup
arg.each do |k,v|
arg[k] = force_utf8_strings(v)
end
arg
else
arg
end
end
これでエラーは出なくなりました。
実は force_utf8_strings は app/models/setting.rb にあるPrivateメソッドをコピーしたもの。
同じコードが二箇所にあることになるので、原則的に良い方法じゃないですよね・・・。
こういった場合はどこに配置するのがいいのでしょう。
※2018/07/05 追記
こちらの方が対応されたように、もう一か所修正が必要なようです。
https://qiita.com/sugasaki/items/296a2e1f8101826ce588
なお最新版のRedmineでも同様の事象が起きる場合の対処ですが
上記パッチ対応後にカスタムクエリーを修正・保存しなおすと、カスタムクエリ上の条件文字列データがUTF-8で保存しなおされるので次からエラーがでなくなることを確認しました。