データベースに関わるアンチパターン
- 既存のmigrationを勝手に修正する
すでにリポジトリに対してcommitされたup
メソッドを編集するべきではない。既存のmigrationを変更してもrake db:migrate
コマンドはすでに実行したことがあるタイプスタンプ名のmigrationを適用しないため、混乱が生じる。
基本的にカラムなどの操作は新たにmigrationをまた作成するべきだ。だが、どうしても既存のmigrationを訂正しないといけないということになった場合は、rake db:migrate:redo
commitされたupメソッドを修正するな、混乱の元だ。
もしどうしてもやるんならrake db:migrate:redoで。これは指定ステップ前までのmigrationを取り消し、やり直してくれる。
ちなみにだが、DBのスキーマ管理について、ridgepoleを使うという選択肢もある。これだと冪等性が確保されるので、このような混乱が生じることはない。
- migration内にRubyコードを入れる。
理論上、up,downメソッドはmigraiton時に実行されるので、こういうことができる(そもそも発想がなかった)
def self.up
add_column :users, :jobs_count, :integer, :default => 0
Users.all.each do |user|
user.jobs_count = user.jobs.size
user.save
end
end
しかしもし使ってるモデル(User)がなくなったらこのmigrationは落ちる。
SQLを直接叩くだと、DBの状態にしか依存しないので少しマシになる。
参考:Railsのmigrationで生SQLを使う+パラメータを使う
もしモデルを参照したい場合はmigrationの中にワンライナークラス定義を含めてしまえばよい。
class Job < ActiveRecord::Base;end
class User < ActiveRecord::Base
has_many :jobs
end
def self.up
add_column :users, :jobs_count, :integer, :default => 0 User.reset_column_information
Users.all.each do |user|
user.jobs_count = user.jobs.size
user.save
end
end
- downメソッドを用意しない
downメソッドがないと、ロールバック時の挙動がコントロールできない。
たとえば、絶対にロールバックしたくないmigrationについてはdownメソッドに例外を仕込んでおくという技がある。こうすると他のメンバーに「このmigrationはロールバックしてはならない」という意図を伝えることができる。
アンチパターン:バリデーション関係
バリデーションをモデル定義にいっぱい書いてる人がいるけど、(今はそれも別クラスに分けられるとはいえ)DBの機能でなんとかできることはそっちの機能を利用したい。が、DBMSによって使える機能が全然違う。
ActiveRecordが提供している機能はだいたいDBMSの最大公約数的な機能だけなので、自分でプラグインを探してくる必要がある。
ここではforeignerが紹介されていたが、Rails4.2では外部キー制約は機能に組み込まれている。たとえば自分はmysqlにunsigned
型を追加したのに、mysql-awesomeを利用している。この辺は界隈の情報更新についていく必要がありそう。