概要
自分が担当しているシステムでユーザーからデータの保存ができないとお問い合わせを受けたことがあります。
システムが高負荷になっていた訳でもなく、そのユーザー以外は普通に利用できていたので、最初は原因が分からなかったのですが、ログを調べて見たらあるエラー吐かれていました。
今回、そのエラーについて調べたときの事をまとめました。
エラー文言
以下のエラーが発生して DB へのデータ挿入に失敗していました。
ActiveRecord::ValueTooLong(Mysql2::Error: Data too long for column 'xxxxx' at row 1: INSERT INTO 'table' ('column1', 'column2', 'column3'....))
原因
対象カラムのデータ型が varchar (255) となっており、ユーザーが挿入しようとしたデータが 255 バイト以上だったため、カラムに格納できる最大バイト数を超えてエラーとなっていました。
解決策
解決策としては 2 つの方法を考えました。
- フロントエンド側で入力フォームの文字数制限を入れる
- 対象カラムのデータ型を変更する
最終的にはどちらも実装した方が良いのですが、今回はユーザーがデータを保存できないエラーを解決したかったので、取り急ぎ対象カラムのデータ型を変更する方法をとりました。
余力があれば、フロントエンド側にテキストボックスの文字数制限を入れようと思います。
また今回、例外処理が入っていなかったので、例外処理の記述も追加したいと思います。
何のデータ型にすれば良いのか?
そもそも varchar (255) にした理由は rails generate scaffold でカラムを生成した際に、string 型で作ろうとしたらデフォルトで設定されたデータ型だったからです。
参考:【Rails・MySQL】MySQLのデータ型とRailsのマイグレーションファイルのデータ定義の対応まとめ
まず初めに変更を考えたデータ型は text 型です。
text 型で格納できるバイト数は 2 の 16 乗なので 65536 バイトとなります。
参考:MySQL :: MySQL 5.6 リファレンスマニュアル :: 11.7 データ型のストレージ要件
しかし、今まで最大 255 バイトで十分だったカラムにいきなり 65536 バイトも設定する必要があるでしょうか?
そこで varchar の最大バイト数を変更する方法を取りました。
具体的には varchar (255) を varchar (500) としました。
mysql> alter table 'table名' modify 'column名' varchar(500);
データ型変更は既存のデータに影響を与える処理なので、本来であれば慎重に行わないといけません。
しかし、今回の変更は最大長を 255 バイトから 500 バイトに変更しただけなので問題が発生する可能性は極めて少ないと思われます。
日本語文字って何バイトか?
ちなみに日本語って何バイトなんだろうと疑問に思いました。
文字コードによって違うようで、全角 1 文字 2 バイトなのは EUC-JP や Shift_JIS を使ったときのようです。
現在主流の UTF-8 を使うと 2 ~ 4 バイトで表されるようです。
例外処理を入れる
最大長を 500 バイトに更新しましたが、それ以上のデータを挿入された場合の為に例外処理を書いておきます。
begin
# ** DB にデータを挿入する処理 **
# 例えば
# # @user.create
# # @user.save
# # など
rescue ActiveRecord::ValueTooLong => e
# ** 例外が発生した場合の処理 **
# 例えば
# # エラーページにリダイレクト
# # return redirect_to '/500.html'
# # エラーログを出力する
# # log.error(e.message)
# # インスタンス変数を使って View 側にメッセージを表示
# # @is_toolong_value = true
# # など
end
まとめ
rails generate scaffold で strign 型のカラムを作成するとデフォルトでは varchar (255) となります。
ユーザー入力では開発者が想定外のものを入力されることが稀にありますので、フロントエンド側でしっかり制御したり、格納できるデータは余裕をもって大きい値にしておく事をお勧めします。