15
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rails + Mysql(utf8mb4) on Amazon RDS

Posted at

まえがき

Mysql5.5以前だと4バイト以上のutf8の文字が入らない。
言い換えると3バイトまでなら入る。

Mysql5.5以降でも意識しないで使うと残念ながら入らない。。
なんじゃこりゃと思ったのでまとめておく。

ちなみにRailsから使う場合で、
MysqlはAmazon RDS上で動いている。

Amazon RDS

これがちょっと厄介で、
Amazon RDSのAPI(もしくはCLI Toolkit)が
utf8mb4に対応していない。

なので、Paramater Groupに設定して、、、ってことは出来ない。
DB作るときに指定しておけばいいんだけど、忘れると悲惨。

Rails

mysql2

大変お世話になっているmysql2ですが、
この時点でutf8mb4に対応していない。

どういうことかというと、database.ymlで

production:
  adapter: mysql2
  database: hogehoge
  encoding: utf8mb4

って書くと怒られる。
unknown charsetとかだったかな?

対応が必要なファイルは、
mysql2/lib/mysql2/client.rb
なんだけど、github見に行くと既にutf8mb4のための更新がされてる。
そのcommit log

なので、bundlerでgit指定してやってもいいし、
乱暴な話、client.rbの該当箇所だけ修正しても良い。

ActiveSupport::JSON::Encoding

レスポンスをJSONで返したくて。
そのまんま返すんであれば読み飛ばして大丈夫。

マルチバイト文字の場合、
ActiveSupport::JSONは律儀にUnicode Escape Sequenceに変換してくれる。

github 該当箇所

一見格好いいけど、これ、\u1234みたいなごく一般的なEscape Sequenceは変換できるけど、
\u{123}とか\u{12345}みたいなEscape Sequenceはミスる。

なのでこんな感じにoverrideした。

module ActiveSupport::JSON::Encoding
  class << self
    def escape(string)
      string = string.encode(::Encoding::UTF_8, :undef => :replace).force_encoding(::Encoding::BINARY)
      json = string.gsub(escape_regex) { |s| ESCAPED_CHARS[s] }


      json = json.gsub(/([\xC0-\xDF][\x80-\xBF]|
             [\xE0-\xEF][\x80-\xBF]{2}|
             [\xF0-\xF7][\x80-\xBF]{3})+/nx) do |s|
        s.unpack("U*").pack("N*").unpack("H*")[0].gsub(/.{8}/n) do |u|
          /^0+(.+)$/ =~ u
          ($1.size == 4) ? "\\u#{$1}" : "\\u{#{$1}}"
        end
      end

      json = %("#{json}")
      json.force_encoding(::Encoding::UTF_8)
      json
    end
  end
end

危ないので良い子の皆さんは真似せず、
pull request送りましょう。

まとめ

こんな感じで動いた。
ただ、Stackoverflowの記事読んだりしていて、
そもそもJSONでレスポンス返すときにEscapeする必要あるの?って議論もあって、なるほどなるほどーって思いました。

15
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?