Emoji

I. What is Emoji?

Emoji (絵文字= picture letter) là thuật ngữ xuất phát từ tiếng Nhật, có thể hiểu là những kí tự hình ảnh, ví dụ như hình mặt cười, biểu tượng cảm xúc như 😄 😮

II. Approach

Mysql 5.5.3+ hỗ trợ mã utf8mb4 để lưu Emoji

III. Implement

1. Config mysql server

Trước tiên là thiết lập 1 vài thông số character-set của mysql server trong file my.conf như sau:

   # my.conf
   [client]
   default-character-set = utf8mb4
   [mysqld]
   character-set-server = utf8mb4
   collation-server = utf8mb4_unicode_ci
   skip-character-set-client-handshake

Sử dụng của sổ dòng lệnh của mysql tạo thử database và kiểm tra variables

   mysql> use sample
   Database changed
   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/share/mysql/charsets/ |
   +--------------------------+----------------------------+
   8 rows in set (0.00 sec)

Như bản variables trên ta thấy ngoại trừ character_set_filesystem và character_set_system thì tất cả giá trị của character-set còn lại đều là utf8mb4. Như vậy là đã hoàn thành xong thiết lập bên phái mysql server.

2. Config rails

Bước tiếp theo là config bên phái rails application. Trong file database.yml chúng ta thêm 3 thuộc tính charset, encoding, collaction như dưới đây để chỉ ra rằng chúng ta sẽ sử dụng mã utf8mb4.

   development:
      adapter: mysql2
      charset: utf8mb4
      encoding: utf8mb4
      collation: utf8mb4_unicode_ci
      reconnect: false

3. Max key length is 767 bytes problem

Mysql giới hạn kích thước của index key là 767 bytes. Với Utf8 sử dụng 3 bytes để mã hoá kí tự nên độ dài tối đa của index key là 255 kí tự. Nhưng Utf8mb4 sử dụng 4 bytes để mã hoá kí tự nên tối đa ta có 767/4 = 191 kí tự. Mà mặc định của khi tạo bảng với index kích thước tối đa của index key là 255 nên xảy ra lỗi như trên. Với rails 4 thì vấn đề này sẽ được giải quyết trọng vẹn, nhưng hiện tại chúng ta dùng rails 3 nên ta phải override một số hàm thư viện của ActiveRecord.

Override some module of ActiveRecord

// SchemaStatement

   module ActiveRecord
      module ConnectionAdapters # :nodoc:
         module SchemaStatements
            MAX_INDEX_LENGTH_FOR_UTF8MB4 = 191
            def initialize_schema_migrations_table
               if @config[:encoding] == 'utf8mb4'
                  ActiveRecord::SchemaMigration.create_table(MAX_INDEX_LENGTH_FOR_UTF8MB4)
               else
                  ActiveRecord::SchemaMigration.create_table
               end
            end
         end
      end
   end
// SchemaMigration

   module ActiveRecord
      class SchemaMigration < ActiveRecord::Base
         def self.index_name
            "#{Base.table_name_prefix}unique_schema_migrations#{Base.table_name_suffix}"
         end

         def self.create_table(limit=nil)
            unless connection.table_exists?(table_name)
               version_options = {null: false}
               version_options[:limit] = limit if limit

               connection.create_table(table_name, id: false) do |t|
                  t.column :version, :string, version_options
               end
               connection.add_index table_name, :version, unique: true, name: index_name
            end
         end
      end
   end

Config length for unique columns of table

Thay đổi giới hạn độ dài cho một số thuộc tính unique

   // db/migrate/*.rb
   add_index :users, :email, unique: true, length: 191

4. Fix json

Đối với những ứng dụng web yêu cầu dữ liệu trả về dưới dạng json, chúng ta cần override module sau để dữ liệu trả về đúng với mã utf8bm4.

   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

IV. Conclusion

Cùng với sự phát triển mạnh mẽ của mạng xã hội và smartphone, Emoji là thứ ko thể thiếu, góp thêm phần thú vị hình tượng khi chúng ta giao tiêp và chia sẻ thông tin qua mạng. Và như hướng dẫn ở trên, ta có thể thấy việc tạo ra 1 ứng dụng web hộ trợ Emoji thật đơn giản với Ruby on rails.