MySQL+ActiveRecord環境で絵文字に対応したお話

[mixiグループ Advent Calendar 2017](https://qiita.com/advent-calendar/2017/mixi) の21日目です。

XFLAGスタジオ CRE(Customer Reliability Engineering)チームの @njin です。

### :triangular_flag_on_post: はじめに
CREチームの業務の一つに、カスタマーサポート(CS)スタッフ向けの管理画面(CSツール)の開発があります。
今回は最近実装したCSツールの機能で起きた問題とその解決方法についてまとめました。

CREとは？CREチームって何やってるの？など
ご興味を持っていただけた方は、こちらの記事もご覧になってみてください。
CREチームのメンバーがAdvent Calendarに参加しております :smile: 
[CREチームを設立しました！](https://career.xflag.com/report/engineer/cre/)(@otoyo)
[アプリケーションサーバに引きこもるDBを自立させてDocker Composeで開発環境を作る](https://qiita.com/upscent/items/8d9ebd1f4f4cc11b12a6)(@upscent)
[なれる！CRE](https://qiita.com/nukosuke/items/ff087fc1fa033a00dbd9)(@nukosuke)
[フェイルセーフの観点から顧客信頼性を確保しよう](https://qiita.com/manji602/items/a1d8c7901eafc636f30c)(@manji602)

### :triangular_flag_on_post: 機能の概要
XFLAGスタジオのCSでは、多くのプロダクトでCS対応にZendeskというCRMを使用しています。
Zendeskではお問い合わせ1件1件を「チケット」と呼ばれるものに紐づけて管理しています。

詳細は書けないのですが、今回追加した機能の簡略化したフローは以下です。
1. ZendeskからAPIでチケット単位のデータ(JSON形式)を取得
2. 取得したチケットのデータをDBへ保存
3. 保存したデータを整形し、CSツールで表示

![Pasted image at 2017_12_15 10_49 AM.png](https://qiita-image-store.s3.amazonaws.com/0/61334/c47a2dca-93c1-0656-f8f4-3beca1c9b221.png)

チケットにはお問い合わせの内容やアカウントのID・ニックネーム・ランクなどが記載されたメール本文が含まれており、ここである問題が発生しました。

### :triangular_flag_on_post: 問題
CSスタッフから連絡があり、CSツールでユーザーの情報が途中から表示されていないというのです。
さらにニックネームに絵文字が含まれていると聞き、嫌な予感がしました…

DBのデータを確認すると、ニックネームから後ろが切れています。

```ruby
[1] pry(main)> ticket.body
=> "【お問い合わせ内容】\r\nhogehogeについて\r\n\r\n【項目1】\r\ntest\r\n\r\n【項目2】\r\ntest\r\n\r\n【ニックネーム】\r\n"
```

テーブルの定義を確認すると、

```sql
> SHOW CREATE TABLE tickets;
| tickets | CREATE TABLE `tickets` (
`body` text NOT NULL,
...
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
```

そうですよね。

テーブル作成時にCHARSETをutf8mb4に設定していないことが原因でした。
テーブルやカラムがutf8mb4に対応していない場合、絵文字(4バイト文字)が含まれているとそれ以降がカットされてしまいます。

```ruby
[1] pry(main)> ticket = Ticket.create(body: "すし🍣すし")
[2] pry(main)> ticket.body
=> "すし"
```

### :triangular_flag_on_post: 解決方法
追加した機能がすでに稼働している状況だったため、テーブルの作り直しではなく、CSの業務時間外に `change_column` を使ったカラム変更でCHARSETをutf8からutf8mb4へ変更することにしました。
`change_column` でCHARSETを変更するための記法がわからず少々苦戦しましたが、以下の記述で変更することができました。

```rb
class ChangeColumn < ActiveRecord::Migration
  def self.up
    change_column :tickets, :body, "text CHARSET utf8mb4"
    ...
  end
end
```

```rb
[1] pry(main)> Ticket.create(body: "すし🍣") 
```
```
SELECT * FROM tickets;
+----+------------------------------+
| id | body                         |
+----+------------------------------+
|  1 | すし????                      |
+----+------------------------------+
```

絵文字以降も保存されるようになりましたが、文字化けした状態で保存されてしまいました。
そこで、[RailsとMySQLでiOSの絵文字に対応(UTF8MB4化)した話](http://akataworks.hatenadiary.jp/entry/2016/02/26/102439)を参考に、ActiveRecordでMySQLへ接続する際のCHARSETをutf8mb4に設定することで解決しました。

```yaml:config/database.yml
development:
  encoding: utf8mb4

test:
  encoding: utf8mb4

production:
  encoding: utf8mb4
```

```rb
[1] pry(main)> Ticket.create(body: "すしすし🍣🍣")
```

```
SELECT * FROM tickets;
+----+------------------------------+
| id | body                         |
+----+------------------------------+
|  1 | すし????                      |
|  2 | すしすし🍣🍣                    |
+----+------------------------------+
```

文字化けせずに保存できました。

### :triangular_flag_on_post: 終わりに
CSツールに不具合が発生しCSツールが停止すると、CSスタッフは対応ができなくなり、それはそのままユーザーさんへの返信の遅れに直結します。

CREチームのメンバーとして、より速く・正確なCS対応のサポートをしていけるように、CSツールの開発についても「より速く・正確な」を意識して取り組んでいきたいと思います。

### 参考URL
[RailsとMySQLでiOSの絵文字に対応(UTF8MB4化)した話](RailsとMySQLでiOSの絵文字に対応(UTF8MB4化)した話)