はじめに
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する)
- my.cnfを変更する
- mysqlをリスタートする
- ActiveRecordにオプションを追加
- database.ymlの変更
- docker-compose.ymlの変更し、コンテナの再起動
- db:migrate:resetを実行
- dumpデータのrestore
準備:dumpする
そもそもこの作業を行うまでdumpという言葉を知らなかったのですが、dumpとはDBのテーブル内の情報をSQLの形で出力することだそうです。(ちなみに最後に行うrestoreは、dumpした情報をDBに投入すること)
今回データベース設定を変更し、各テーブルの文字コードをutf8mb4にするので、一旦データをファイルとして落としておいて、設定変更後に投入するという形をとりります。
dump/restoreを簡単に行うために以下のgemを使用します。
gem 'yaml_db'
今回使用するのはyaml_dbという、ダンプでyaml形式ファイルを出力してくれるgemです。
GitHub - yamldb/yaml_db
dumpするには以下のコマンドをすればOK
bundle exec rails db:data:dump
コマンド実行後、db/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行ずつ見ていきました。
[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内のコンテナに入り以下のコマンドを実行します。
もともとの設定を一応確認しておきます
mysql>status;
:(中略)
Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
:
utf8になっています。
というわけで、一旦リスタートして、もう一度みてみます。
mysql>service mysql restart
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が起動する前に初期設定として読み込まれるようになります。
#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の変更
以下の内容を追加ないし変更します
charset: utf8mb4
encoding: utf8mb4
collation: utf8mb4_general_ci
5. docker-compose.ymlの変更
Dockerの設定ファイルも以下のように変更します。
:
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できます。
rails db:data:load
以上で設定は完了です!
終わりに
色々と設定してきましたが、dumpなどの機能を知ることができたので、いい勉強になりました。
全面的に参考にさせていただいたサイト様
大変ありがとうございます・・・!
・MySQLのencodingをutf8からutf8mb4に変更して寿司ビール問題に対応する
・RailsのDBバックアップ(gem:yaml_db)
・Rails5で絵文字を保存する utf8mb4 (docker)