1
0

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 3 years have passed since last update.

[Rails5.2] Docker内のMysql 5.7の絵文字対応(文字コードをutf8mb4に変更する)

Posted at

はじめに

Ruby on Railsでポートフォリオを作成しているRails初学者です。
今回はタイトルの通り、tableに絵文字情報を保存するためのmysqlをutf8mb4にした際の覚書です。

Youtube Data APIから動画タイトルを保存しようとしたらエラーが出た。

ActiveRecord::StatementInvalid in VideosController#refresh
Mysql2::Error: Incorrect string value: '\xF0\x9F\x94\xB5\xE8\x87...'

絵文字が入っているタイトルがいくつかあり、それが影響でエラーが出たようです。
mysql上のdbの文字コードを見るとuft8になっており、これを変更しなければいけない様子・・・
ひとまず色々なコードを参考にして以下の通りに実施しました。

環境

Docker for mac を使ってコンテナ内でRailsを開発しています。

ruby 2.4.5
mysql 5.7.31
Ruby on rails 5.0.7.2

流れ

(準備:dumpする)

  1. my.cnfを変更する
  2. mysqlをリスタートする
  3. ActiveRecordにオプションを追加
  4. database.ymlの変更
  5. docker-compose.ymlの変更し、コンテナの再起動
  6. db:migrate:resetを実行
  7. dumpデータのrestore

準備:dumpする

そもそもこの作業を行うまでdumpという言葉を知らなかったのですが、dumpとはDBのテーブル内の情報をSQLの形で出力することだそうです。(ちなみに最後に行うrestoreは、dumpした情報をDBに投入すること)

今回データベース設定を変更し、各テーブルの文字コードをutf8mb4にするので、一旦データをファイルとして落としておいて、設定変更後に投入するという形をとりります。

dump/restoreを簡単に行うために以下のgemを使用します。

Gemfile
gem 'yaml_db'

今回使用するのはyaml_dbという、ダンプでyaml形式ファイルを出力してくれるgemです。
GitHub - yamldb/yaml_db

dumpするには以下のコマンドをすればOK

Terminal
bundle exec rails db:data:dump

コマンド実行後、db/data.ymlにファイルが出力されています。
こんな感じで、基本的にはテーブル名、カラム情報、レコードの順番で出力されます。

data.yml
videos:
  columns:
  - id
  - name
  - url
  - upload_at
  - created_at
  - updated_at
  records:
  - - 1
    - "【衝撃】ボーナス支給額をクイズで決める会社"
    - https://www.youtube.com/watch?v=42ofwfioMFM
    - 2020-10-09 09:00:00.000000000 Z
    - 2020-10-10 08:07:38.000000000 Z
    - 2020-10-10 08:07:38.000000000 Z
 :

以下で準備はOKです。

1. my.cnfを変更する

my.cnfファイルを以下のように設定します。
記載されている内容をきちんと理解したかったため、1行ずつ見ていきました。

my.cnf
[mysql]
default-character-set=utf8mb4 #文字コードの設定

[mysqld] #mysqld Mysqlサーバの設定
character-set-server = utf8mb4 #文字コードの設定
skip-character-set-client-handshake #client側で指定した文字コードを無視するためのもの
collation-server = utf8mb4_general_ci #ソート順の指定
init-connect = SET NAMES utf8mb4 #クライアントからserverへの送信に使用される文字セット指定

各項目について、細かく見ていきます。

[mysql]と[mysqld]
mysqldとは、MySQLサーバとも呼ばれる、mysqlでの各種操作を受け持っているメインプログラムのこと。
mysql側の操作は必ずこのmysqldよりされるため、ここに各種設定が必要。

skip-character-set-client-handshake
character-set-client-handshakeとは、クライアント側の文字コードをMySQL側に反映する行為。これをスキップすることで、uft8mb4への設定ができる。

collation-server = utf8mb4_general_ci
collationは、照合順序:ソート順のこと。_で区切られた各単語でそれぞれ設定。
詳細は以下を参照
【MySQL】照合順序とは?

init-connect = SET NAMES utf8mb4
クライアントからサーバへの送信に使用される文字コードの指定
詳細は以下を参照
10.1.4 接続文字セットおよび照合順序

2. mysqlをリスタートする

ひとまず、この設定を反映するためにmysqlをリスタートします。
Docker内のコンテナに入り以下のコマンドを実行します。

もともとの設定を一応確認しておきます

terminal
mysql>status;
:(中略)
Server characterset:	utf8
Db     characterset:	utf8
Client characterset:	utf8
Conn.  characterset:	utf8
:

utf8になっています。
というわけで、一旦リスタートして、もう一度みてみます。

terminal
mysql>service mysql restart
terminal
mysql>status
:(中略)
Server characterset:	utf8mb4
Db     characterset:	utf8mb4
Client characterset:	utf8mb4
Conn.  characterset:	utf8mb4
:

設定できました!

3. ActiveRecordにオプションを追加

次に、ActiveRecordのcreate_tableが実行される際に、utf8mb4を使って登録するよう設定していきます。

新しくconfig/initializers/utf8mb4.rbを作成し、以下のコードを記載。
config/initializersにファイルを投入すると、Railsが起動する前に初期設定として読み込まれるようになります。

config/initializers/utf8mb4.rb
#optionを設定するmodule
module Utf8mb4
  def create_table(table_name, options = {})
    table_options = options.merge(options: 'ENGINE=InnoDB ROW_FORMAT=DYNAMIC')
    super(table_name, table_options) do |td|
      yield td if block_given?
    end
  end
end

ActiveSupport.on_load :active_record do
  module ActiveRecord::ConnectionAdapters
    class AbstractMysqlAdapter
      #最初にmodule utf8mb4を実行し、その後既存のメソッドを実行(super)      
      prepend Utf8mb4
    end
  end
end

4. database.ymlの変更

以下の内容を追加ないし変更します

config/database.yml
  charset: utf8mb4
  encoding: utf8mb4
  collation: utf8mb4_general_ci

5. docker-compose.ymlの変更

Dockerの設定ファイルも以下のように変更します。

docker-compose.yml
:
  db:
    image: mysql:5.7
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci #utf8mb4をセット 
    container_name: コンテナ名
    volumes:
      - ./my.cnf:/etc/mysql/conf.d/my.cnf #my.cnfを読み込むよう設定
 :

この状態で、一度コンテナを再起動します。

6. db:migrate:resetを実行

ここまでのDBへの設定を反映させるため、DBをリセット→migrateします。

7. dumpデータのrestore

最後に、冒頭でdumpしたデータをもう一度投入すれば完了です。
以下のコマンドでrestoreできます。

terminal
rails db:data:load

以上で設定は完了です!

終わりに

色々と設定してきましたが、dumpなどの機能を知ることができたので、いい勉強になりました。

全面的に参考にさせていただいたサイト様
大変ありがとうございます・・・!
MySQLのencodingをutf8からutf8mb4に変更して寿司ビール問題に対応する
RailsのDBバックアップ(gem:yaml_db)
Rails5で絵文字を保存する utf8mb4 (docker)

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?