ぴよログ

↓に移転したのでこっちは更新されません、多分。

t.string :urlってやっちゃう #あるある

移転しました →

URLを入れておきたいカラムなのにRailsマイグレーションt.string :urlって書いてvarchar(255)にしちゃって、実際の運用で日本語URLがエンコードされて渡ってきて余裕でオーバーするっていうのはあるあるじゃないですか?それとも初心者あるある?

URLに文字数制限ってのは確か存在しなくて、IEかなんかでは2083文字までは大丈夫などアプリケーションによって異なるらしい。

Internet Explorer では URL に最大 2,083 文字が使用可能Internet Explorer では URL に最大 2,083 文字が使用可能はてなブックマーク - Internet Explorer では URL に最大 2,083 文字が使用可能

で、僕はこのミスをRSSリーダーのときにやった。RSSフィードを解析すると各記事のタイトルやらURLが取れるんだけど、そのURLの保存先をvarchar(255)にしていてINSERTできないって問題に当たってしまった。

これを何も考えずに解決するだけであれば簡単で、Railsであれば、t.string :urlt.text :urlなどにしてしまえばOK。文字制限なくなるし。

あとはt.string :url, limit: 1024みたいにlimit使うってのもありだけど、なんかうまくいかないこともあったような。

ついでに話しておくと、MySQLのデフォルトでは768バイト以上の文字列にインデックスを付けることができない。なのでvarchar(256)以上の文字列はインデックスを付けられないようだ。

MySQLのUNIQUEなINDEXには長さ767byteまでしか使えない件と対策 - tanamonの日記MySQLのUNIQUEなINDEXには長さ767byteまでしか使えない件と対策 - tanamonの日記はてなブックマーク - MySQLのUNIQUEなINDEXには長さ767byteまでしか使えない件と対策 - tanamonの日記

このページの解決策には掲載されていないが、MySQL5.5系だとinnodb_large_prefixというオプションを有効にした上で、ROW_FORMATをDynamicやCompressedに変更したテーブルでのみ3072バイトまで使えるようになる。これを使うとvarchar(1024)とかでもインデックスを付けられるようになってしまう!

ちなみにこれをRailsマイグレーションにするにはSQLを直接実行するしかなさそう。こういう風にかいた。changeではなく、従来型のupdownを用いてロールバックもできるように書いている。

class ChangeRowFormat < ActiveRecord::Migration
  def up
    execute 'ALTER TABLE feeds ROW_FORMAT=Dynamic'
  end

  def down
    execute 'ALTER TABLE feeds ROW_FORMAT=Compact'
  end
end