ActiveRecordでinteger型の項目をマイグレして、int型の最大値以上の数を入れて保存しようとすると、モデル側で以下のエラーが出ます。

最大値のエラーなのでエラー自体には納得なんですが、この手のエラーはバリデーションでerrorsに格納してほしいなーと思い、ソースコードを読んでみました。

新規作成時はdatabase_statement.rbのinsertメソッドが呼び出され、

  • ActiveRecord::ConnectionAdapters::DatabaseStatement#to_sql
  • BindCollector#compile
  • ActiveRecord::ConnectionAdapters::Quoting#prepare_binds_for_database
  • ActiveRecord::Attribute#value_for_database

とメソッドが呼ばれていきます。

binds変数にはQueryAttributeの配列が入ります。int型の項目の場合はQueryAttributeオブジェクトのtypeにはType::Integer型のオブジェクトが入ります。このType::Integerのserializeでrangeチェックをしていて、range外の場合はRangeErrorがraiseされます。

MySQLの場合は以下のTypeMapの設定によってMySQLの型からRubyオブジェクトのType::XXXに変換されます。intの場合はlimit: 4、bigintの場合はlimit: 8のように、項目によってrangeの桁数が変わります。MySQLの項目型の判定は正規表現マッチを使っています。

項目の型はSHOW FULL FIELDS FROMで取得しています。