黒縁眼鏡は海を飛ぶ

IT中心にそこはかとなく

ActiveRecordのMigrationを単体で使う

85,000番煎じです。
Railsについての知識がないのですが、よく見かけるコマンドrake db:migrate
これがめっちゃ便利で、かつ非RailsなアプリでもActiveRecord単体で使えるらしいので使ってみた。
どうでもいいですがmigrateは移動とか移住って意味です。なるほど。


ディレクトリ、ファイルの準備

ガシガシとコマンドを投入していく。

mkdir -p db/migrate
touch db/migrate/001_create_samples.rb
touch db/migrate/002_add_tag_for_samples.rb
touch Rakefile

とりあえず空ファイルができた。


migration用のファイルを編集

例として作成するテーブルの構成は以下のような感じ。

  • テーブル名
    • samples
  • カラム
    • id(pk)
    • body(varchar)
    • tag(varchar)

001_create_samples.rbでテーブル作成とid, bodyカラムの追加。 002_add_tag_for_samples.rbtagカラムを追加したいとします。

001_create_samples.rbは以下のように。

class CreateSamples < ActiveRecord::Migration
  def up
    create_table :samples do |t|
      t.string :body
    end
  end

  def down
    drop_table :samples
  end
end

002_add_tag_for_samples.rbは以下のように。

class AddTagForSamples < ActiveRecord::Migration
  def change
    add_column :samples, :tag, :string
  end
end

ハマった・調べたポイントは、

  • mingration用のrubyスクリプトのファイル名とclass名は紐付ける必要がある
  • up, downはそれぞれmigrateとrollback時の処理を定義するときに使う
    • rollbackする時の処理を書いてないと困るとき(upremove_columnがあったり)
  • changeはそれひとつでmigrate時に実行される処理を反転した処理をrollback時に実行してくれます


Rakefile作るぞ!

兼ねてからRake学ぶと嘯いていますが、盗みみながらようやっと書きました。

require 'active_record'
require 'yaml'

namespace :db do
  migrate_dir = 'db/migrate'

  config = YAML.load_file('config/database.yml')
  ActiveRecord::Base.establish_connection(config['db']['development'])

  desc 'Migrate db'
  task :migrate do
    ActiveRecord::Migrator.migrate(migrate_dir, ENV['VERSION'] ? ENV['VERSION'].to_i : nul)
  end

  desc 'Roll back db'
  task :rollback do
    ActiveRecord::Migrator.rollback(migrate_dir, ENV['STEP'] ? ENV['STEP'].to_i : 1)
  end
end

VERSIONSTEPを指定することでmigrateとrollbackの粒度を指定できるようになってます。


いざ実行!

ではさっそく実行してみましょう。

$ bundle exec rake -T
rake db:migrate   # Migrate db
rake db:rollback  # Roll back db

タスクが登録されております。
この調子でmigrateします。

$ bundle exec rake db:migrate
== 1 CreateSamples: migrating =================================================
-- create_table(:samples)
-> 0.0086s
== 1 CreateSamples: migrated (0.0087s) ========================================

== 2 AddTagForSamples: migrating ========================================================
-- add_column(:samples, :tag, :string)
-> 0.0005s
== 2 AddTagForSamples: migrated (0.0006s) ===============================================

ホントに処理が走ったから接続して見てみます。

$ psql -U dbuser -d testdb
testdb=> \d samples
Table "public.samples"
 Column |       Type        |                      Modifiers                       
--------+-------------------+------------------------------------------------------
 id     | integer           | not null default nextval('samples_id_seq'::regclass)
 body   | character varying | 
 tag    | character varying | 
Indexes:
"samples_pkey" PRIMARY KEY, btree (id)

できてるー!やったー!

rollbackもしてみます。

$ bundle exec rake db:rollback
== 2 AddTagForSamples: reverting ========================================================
-- remove_column(:samples, :tag, :string)
-> 0.0008s
== 2 AddTagForSamples: reverted (0.0030s) ===============================================
testdb=> \d samples
Table "public.samples"
 Column |       Type        |                      Modifiers                       
--------+-------------------+------------------------------------------------------
 id     | integer           | not null default nextval('samples_id_seq'::regclass)
 body   | character varying | 
Indexes:
"samples_pkey" PRIMARY KEY, btree (id)

tagカラムが消えてますね。

ちなみに一気にrollbackしたい時はSTEPに値を指定してやればよいです。

$ bundle exec rake STEP=2 db:rollback


所感

テーブル編集の履歴が残っていい感じっぽい。
Rakefileにmaigrationのログを吐くように処理を追記すればなおよさげ。
複数テーブルの扱いは明日やる。


謝辞

rake db:migrateで、uninitialized constant hogehoge - xengineer's diary -
【Rails】migrationのchangeとup/downって何が違うの? - tanihiro.log -
新しいマイグレーションを追加してテーブルを変更 - RubyLife -