読者です 読者をやめる 読者になる 読者になる

rails mysqlでiPhoneアプリの絵文字対応

超久しぶりの更新 大丈夫生きてます。

色々あって今iPhoneアプリを作っていて
そのアプリで絵文字を使いたくて結構はまったので、対応したメモを残しておく。

ユーザーがDBに突っ込んでくるテキストに絵文字が入っていてrailsとDBはmysqlを使ってる。

Mysql2

railsでmysql2を使ってるが、gem mysql2がutf8mb4に対応していないので
下記を参考にbundleで入れたmoduleに手を入れた。

AWS - Rails + Mysql(utf8mb4) on Amazon RDS - Qiita
add utf8mb4 charset · f535df8 · brianmario/mysql2 · GitHub

mysql2の更新が待たれる。。。

Gemfileに下記を追加してもいいかも

gem 'mysql2', :git => 'git://github.com/tmtm/mysql2.git', :branch => 'utf8mb4'

database.ymlを変更しエンコードをutf8 -> utf8mb4に変更する

production:
  adapter: mysql2
  database: test
  encoding: utf8mb4

databaseをutf8mb4で作成する

create database test DEFAULT CHARACTER SET utf8mb4;

DBをマイグレーションする
※ utf8(3バイト) -> utf8mb4(4バイト)になったことにより
primary key, unique keyインデックスのbyteが767以上になってしまうカラムがあるのでVARCHARカラムなどは適切な値で正規化する

MySQLのUNIQUEなINDEXには長さ767byteまでしか使えない件と対策 - tanamonの日記

railsがデフォルトで作るschema_migration用のversionカラムも上記に該当するのでversionカラムをVARCHAR(15)に変更する

Rails3 と MySQL な環境で Unicode の絵文字を使う - SmallStyle(2011-12-05)

/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/abstract/schema_statements.rb
419行目を修正

schema_migrations_table.column :version, :string, :null => false, :limit => 15


railsからはJSONでアプリにレスポンスを返す仕様
jsonで出力する際にrailsがマルチバイト文字をescapeしている。
※下記が該当コード
http://blog.sosedoff.com/2012/04/26/emoji-and-rails-json-output-issue/

しかしこれは \u{123}とか\u{12345}みたいな4バイト以上の文字はescapeをミスる
Emoji range encoded in JSON mangled · Issue #3727 · rails/rails · GitHub

escapeを行っている ActiveSupport::JSON::Encodingを下記のようなファイルを作って対応

config/initializers/active_support_encoding.rb

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

参考 : http://blog.sosedoff.com/2012/04/26/emoji-and-rails-json-output-issue/

これでなんとか対応できた。