現象
- 複数台いるサーバからmigrateで、とあるテーブルにカラム追加(デフォルト値あり)
- カラム追加したテーブルのモデルをfind、追加したカラムの値を更新するとDBに反映されない
- カラム追加したテーブルのモデルをnew+saveして、追加したカラムの値を更新しようとすると例外発生
ハマりどころ
- 複数台いるサーバのプロセスのうち、上記の現象が発生しないプロセスがいる
- サーバはpassengerで起動
- 起動後~マイグレまで寝ていたプロセスがマイグレ後に起こされたら、DBスキーマをそのとき初めてメモリにロードする?(ここでは深追いしてない)
原因
migrate後~rails再起動の間のActiveRecordの挙動のよう。
findとcreateしたモデルでは挙動が異なったのでそれぞれまとめる。
findしたモデルのマイグレ前後のupdate_attributes
- findしたモデルは追加したカラムの値を読める
- findしたモデルは追加したカラムに対してupdate_attributesするとログからは成功したように見える
- DBのコミットログは流れる
- モデルから属性にアクセスすると値が更新できてない
- 実際にDBを見にいくと、カラムの値が更新されてない
再現手順
#===== マイグレ前 =====
user = User.first
user.hoge
#=> NoMethodError: undefined method `hoge'
user.update_attributes!({ :hoge => "updated" })
#=> ActiveRecord::UnknownAttributeError: unknown attribute: hoge
#===== 別コンソールでmigrate実行(hogeカラム作成) =====
user.hoge
#=> NoMethodError: undefined method `hoge'
user.update_attributes!({ :hoge => "updated" })
#=> ActiveRecord::UnknownAttributeError: unknown attribute: hoge
#===== ユーザオブジェクトを取り直して再実行 =====
user = User.first
user.hoge
#=> "default"
user.update_attributes!({ :hoge => "updated" })
#=> true (DBのコミットログは流れるが、DBを直接見ても更新されていない)
{code}
new+saveしたモデルのマイグレ前後のupdate_attributes
- new+saveしたモデルは追加したカラムの値を読めない
- new+saveしたモデルは追加したカラムに対してupdate_attributesできない
再現手順
user = User.new(:name => "Foo")
user.save!
user.hoge
#=> NoMethodError: undefined method `hoge'
user.update_attributes!({ :hoge => "updated" })
#=> ActiveRecord::UnknownAttributeError: unknown attribute: hoge
#===== 別コンソールでmigrate実行(hogeカラム作成) =====
user.hoge
#=> NoMethodError: undefined method `hoge'
user.update_attributes!({ :hoge => "updated" })
#=> ActiveRecord::UnknownAttributeError: unknown attribute: hoge
# ユーザ作り直して再実行
user = User.new(:name => "Bar")
user.save!
user.hoge
#=> NoMethodError: undefined method `hoge'
user.update_attributes!({ :hoge => "updated" })
#=> ActiveRecord::UnknownAttributeError: unknown attribute: hoge
結論
- マイグレしたらRails再起動しましょう!