なんですかこれは

データベース構造をバージョン管理する仕組み

SQLではなくRubyのコードでデータベース構造を記述することによって抽象化

  • 本番環境への変更の適用漏れがなくなる
  • ほかの開発環境や検証環境への変更の適用がバッチリ
  • 必要があれば以前のバージョンに戻せる
  • 複数のデータベースエンジンへの対応が簡単にできる
    • MySQL, PostgreSQL, SQLite, SQL Server, Sybase, Oracle (メジャーなものはDB2以外ぜんぶだって)

どうつかいますか

$ svn up
$ rake migrate

セットで使う。

これで手元の開発環境のソースコードとデータベースの構造が最新のものになる。

仕組み

schema_infoというテーブルとMigration定義ファイルの名前でバージョン管理

Migration関連の操作

rake db:schema:dump (rake db_schema_dump)

db/schema.rbにデータベース構造をダンプする。

# This file is autogenerated. Instead of editing this file, please use the
# migrations feature of ActiveRecord to incrementally modify your database, and
# then regenerate this schema definition.

ダンプされたファイルの最初の三行。 このファイルを編集して使うんじゃなくてMigrationを使ってくれと言っている。

既存のデータベースがあって途中からMigrationをはじめる場合はこのファイルを元に最初の定義ファイルを作っていくと良い。

このときunsignedなど抽象表現でサポートしてない構造は消えてしまうので注意。

rake db:schema:load (rake db_schema_import)

db/schema.rbの内容をデータベースに反映する。

普通は使わない?

./script/generate migration MigrationName

Migration定義ファイルの雛形を作成する。

class Hoge < ActiveRecord::Migration
def self.up
end

def self.down
end
end

rake migrate

Migration定義ファイルの内容をすべて開発用のデータベースに反映する。

rake migrate VERSION=1

Migration定義ファイルの内容に従ってデータベースの構造を指定されたバージョンの状態に戻す

※バージョンを戻す場合はsvnより先にmigrate(定義ファイルがなくなると元に戻せない)

rake migrate RAILS_ENV=production

本番環境へのMigration

Migration定義ファイルの書き方

ファイル名とバージョン

ファイル名の先頭にバージョン番号を入れる

001_create_gadgets.rb
002_migration_test.rb

ファイル名とクラス名はそろえないとダメ

ファイル名のバージョン番号は現在あるファイルをもとに作られるので、複数人で開発してるとバッティングしてしまうこともあり得る そういう場合はバージョン戻したりして適宜調整。

self.upとself.down

バージョンを進めるときにself.upが実行されて、バージョンを戻すときにself.downが実行される。

この整合性が取れてないとバージョンを戻したときにおかしなことになる可能性がある。

できること一覧

  • create_table(name, options)
  • drop_table(name)
  • rename_table(old_name, new_name)
  • add_column(table_name, column_name, type, options)
  • rename_column(table_name, column_name, new_column_name)
  • change_column(table_name, column_name, type, options)
  • remove_column(table_name, column_name)
  • add_index(table_name, column_name, index_type)
  • remove_index(table_name, column_name)

カラムの型

抽象表現 Ruby型 PostgreSQL型 MySQL型
:primary_key Fixnum serial primarykeyint(11)DEFAULTNULLauto_incrementPRIMARYKEY
:string String charactervarying(255) varchar(255)
:text String text text
:integer Fixnum integer int(11)
:float Float float float
:datetime Time timestamp datetime
:timestamp Time timestamp datetime
:time Time timestamp datetime
:date Date date date
:binary String bytea blob
:boolean Object boolean tinyint(1)
  • MySQLの数値型
    • :integer, :limit => 3 → tinyint
    • :integer, :limit => 5 → smallint
    • :integer, :limit => 7 → mediumint
    • :integer, :limit => 10 → int
    • :integer, :limit => 20 → bigint

unsignedにはできないぽい?

BLOB型とかも桁数指定でtinyblobとかになります。

カラムのオプション

:limit 数値で桁数指定
:default デフォルト値を指定
:null true or false

生SQLも

  • execute(sql)

どうしてもunsignedつけたいときとか。

スキーマ変更以外のデータメンテにも

どうぞ

参考にしたページ

おまけトピックス

本番運用

なめてると意外と難しい

httpd

  • Apache+Fast-CGI
    • 設定かなりめんどい
    • 2.0だと不安定
    • とはいえApacheで動かさざるを得ない場合は多い
  • lighttpd+Fast-CGI
    • 設定それなりにめんどい
    • 事実上Railsの標準?
  • mongrel
    • 簡単ではやい(らしい)
    • 台頭中
  • WEBrick
    • 簡単だしパフォーマンスもそこそこ
    • アクセスが少なければコレで十分
  • Apache+CGI
    • ナローバンドの時代に逆戻りしたかのような懐かしさを覚える
    • ダメ、絶対

データベース

  • development,test,productionの環境の違いに注意
  • database.ymlはリポジトリに入れるべきなんだろうか
  • 多少の学習コストを払ってもMigrationを使ったほうがいい

Railsバージョン互換性問題

Railsのバージョンが変わるとアプリが動かなくなる。 freezeしとくとvender以下に特定バージョンのRailsを置いておけるので平気。

  • rake rails:freeze:gems - 現在インストールされてるバージョンを使用。普段はたぶんこれ。
  • rake rails:freeze:edge - RailsリポジトリのHEADを持ってくる。たぶん実験とかするときに使う。
  • rake rails:freeze:edge TAG=rel_1-1-2 - Railsのリポジトリから指定タグのバージョンを持ってくる

Capistrano

  • 古いディストリだとrubyのopensslのライブラリが鬼門な気がする
  • database.ymlリポジトリからいつも持ってくる
  • すべてのサーバにRubyとrakeとrailsを入れないとダメでユーザも作らないとダメなのがめんどい
  • けどRailsアプリをスケールアウトするならコレ

開発環境どうする

  • ローカルで編集してアップ
    • scp
    • rsync
  • リモートのファイルを直接編集
    • エディタのリモートファイル編集機能
    • samba
  • そもそもLinuxマシンをクライアントに
  • WindowsにRailsを入れる
    • Cygwin上に入れたものはほぼ問題なく動くようだ
    • ローカル開発万歳
  • Mac Bookを買う
  • このエントリーをはてなブックマークに追加
エンジニア募集中です!