Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
25
Help us understand the problem. What is going on with this article?
@ikm

Rails 3.2でiOS5の絵文字を扱う

More than 5 years have passed since last update.

iOS5の絵文字は4バイトのUTF-8で記述されているので、それに対応したPostgreSQLやMySQL 5.5.3以降が必要。

ここではMySQL 5.5を利用する。

MySQLでutf8mb4を扱う

前述した通り、MySQLで4バイトのUTF-8を扱うにはMySQL 5.5.3以上でキャラクタセットにutf8mb4を使う必要がある。

MySQLサーバ

たぶんキャラクタセット関係にはutf8mb4を設定しておいた方がいい。
character_set_systemcharacter_set_filesystem以外はクライアントーサーバ間の通信と保存に使われるので、適切に設定されていないとちょん切られてしまったりすると思う。要検証

mysql> show variables like 'char%';
+--------------------------+------------------------------------------------------+
| Variable_name            | Value                                                |
+--------------------------+------------------------------------------------------+
| character_set_client     | utf8mb4                                              |
| character_set_connection | utf8mb4                                              |
| character_set_database   | utf8mb4                                              |
| character_set_filesystem | binary                                               |
| character_set_results    | utf8mb4                                              |
| character_set_server     | utf8mb4                                              |
| character_set_system     | utf8                                                 |
| character_sets_dir       | /usr/local/Cellar/mysql/5.5.10/share/mysql/charsets/ |
+--------------------------+------------------------------------------------------+

ActiveRecordからの接続

で、mysql2 gemの最新リリースの0.3.11ではutf8mb4に対応していないので、未だに取り込まれていないパッチを自分であてるか、Gemfileで次のようにブランチを指定する(自分はこっちをやってる)。

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

database.ymlのencodingcharsetにutf8mb4を指定する。

development:
  adapter: mysql2
  charset: utf8mb4
  encoding: utf8mb4
  collation: utf8mb4_general_ci
  reconnect: false
  database: myapp_development
  pool: 5
  username: root
  password:
  socket: /tmp/mysql.sock

charsetを指定するのは、CREATE DATABASEDEFAULT CHARACTER SETに使われるから(デフォルトはutf8)。なんでencodingに統一されていないんだろう?

ユニークインデックスのバイト数制限

MySQLのユニークインデックスは767byteまでしか使えないという制限があるため、767byteわる4で191文字までしか使えない。

例えばschema_migrations.versionはvarcharでユニークインデックスがはられているが、デフォルトでは255文字が割り当てられているのでマイグレーションを実行したときにエラーが出る。

実際には14文字しか使わないので、varchar(15)に変更する。

$ bundle open activerecordからlib/active_record/connection_adapters/abstract/schema_statements.rbの419行目あたりを書き換える。

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

ただ本番のgemを書き換えるのも嫌なので、自分はconfig/initializers/active_record_schema_migrations_version.rbActiveRecord::ConnectionAdapters::SchemaStatements#initialize_schema_migrations_tableをそのままコピーして、該当箇所だけ書き換えている。

またschema_migrations.version以外にも自分でユニークインデックスをはる場合には:lengthオプションで191文字以下がインデックス対象になるようにする必要がある。

intとvarcharで複合インデックスをはる際には:lengthを細かく指定できるので気をつけて。

add_index :entries, [:user_id, :url],
      unique: true, length: { url: (191-4) },
      name: "index_on_feed_entries"

JSON

ActiveRecord::JSON::Encoding.escapeは4バイト以上の文字のエスケープに失敗するので、今はJSON gemを使ってる。

config/initializers/active_support_json_encoding.rbにこんな感じ:

module ActiveSupport
  module JSON
    module Encoding
      class << self
        def escape_with_json_gem(string)
          ::JSON.generate([string])[1..-2]
        end
        alias_method_chain :escape, :json_gem
      end
    end
  end
end

JSON gemを使わなくても自分でちゃんとエスケープしてあげる方法もある。

参考資料

(ちなみに)WebSocket/Node.js

WebSocketにNode.jsを使う場合、JavascriptのエンジンであるV8が4バイトのUTF-8に対応していないので、URLエンコードなどの適当な変換をかけてからデータを渡してあげる。

URLエンコードだとこんな感じ:

# Rails側
encoded = Rack::Utils.escape(mb_string)

// JS側
var mbString = decodeURIComponent(encoded).replace(/\+/g,  " ");

Android, iOS4はどうするの?

  • iOS4からiOS5で絵文字のキャラクタ・セットが変わったけど、iOS5ではiOS4の絵文字を表示できるので、iOS5からの絵文字をすべてiOS4のものに変換してしまうのがいいかもしれない。
    • でもそれもいつまで有効なんだろうなぁ…。
  • Androidは知らん
    • NaverのLINEががんばってる、気がする。
25
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ikm
Web Developer. Ruby/Rails, Javascript/Coffeescript, Objective-C.

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
25
Help us understand the problem. What is going on with this article?