マイグレーション

  • マイグレーションは、Railsで提供される移行(マイグレーション)ツールだね。
    • 単に、テーブルを作るだけじゃなく、開発途中でのスキーマ変化で便利らしい
  • 仕組みとしては、こんな感じで動くみたい
    • まず、rails generateコマンド実行時に、マイグレーションファイルを生成
      • db/migrate/20111101220357_create_books.rb みたいなファイルだね
      • ファイル名の先頭の数字は、タイムスタンプね
    • 次に、rakeコマンドで、 未実行の マイグレーションファイルを自動実行
      • 未実行の 判定のため、DBに「schema_migrations」テーブルがあって、実行したマイグレーションのタイムスタンプが入ってるんだ!
      • ちなみに、schema_migrationsのcreate文はこんな感じ
        CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL);
        
    • で、必要に応じて、ロールバックとかをこの辺で管理するみたい
  • マイグレーションファイルは、こんな感じ
    class CreateBooks < ActiveRecord::Migration
     def change
       create_table :books do |t|
         t.string :isbn
         t.string :title
         t.integer :price
         t.string :publish
         t.date :published
         t.boolean :cd
    
         t.timestamps
       end
     end
    end
    
    • うーん、本とバージョンが違うのか、up/downじゃなく、changeのみだなー。
    • まあ、とにかくここにいろいろと書いて、DBのセットアップ&変更を行うのね。
    • で、このcreate_tableでテーブルを作る、と。
      • ここではオプションが無いけど、いろんなオプションも付けられる
        オプション デフォルト 概要
        :id true 主キーカラムidを生成するか
        :primary_key id 主キーの名前
        :temporary false 一時テーブルを作るか
        :force false テーブル生成時に、元テーブルを削除するか
        :options なし その他のオプション
      • 例としては、キーを削除した場合の20111106224619_create_authors_books.rbだと、こんな感じね。
        class CreateAuthorsBooks < ActiveRecord::Migration
         def change
           create_table :authors_books , :id => false do |t|
        
      • ちなみにこのオプションの最後の「:option」は、意外に使うらしい。例としてMySQLのトランザクション使う場合は、こんな感じ
        :options => 'ENGINE=InnoDB'
        
    • 後は、見ての通り、create_tableのループ内で、各カラムを定義する感じ
      • まあ大半は、普通のDB型なんだけど、以下見たいにちょっと面白いのもある
        timestamps 日付型のcreated_at/updated_atを生成
        references 外部キーを生成
      • 各カラムでもいろんなフラグを設定できる
        :limit カラムの桁数
        :default デフォルト値
        :null NULL値を許可するか
        :precision decimal型で、カンマを含んだ全体の桁数
        :scale decimal型で、小数点以下の桁数
  • マイグレーションファイルの作成方法は2種類
    • rails generate modelで、モデルと一緒に作る
      • まあ、こっちは今までもやってきたから、いいでしょう
    • rails generate migrationで、マイグレーションファイルだけで作る
      • こっちは、既存テーブルへの変更用だね。
      • 例えば、Authorテーブルに日付型のbirthカラムを追加する場合は、こんなコマンドになる、と。
        rails generate migration AddBirthToAuthors birth:date
             invoke  active_record
             create    db/migrate/20111221221234_add_birth_to_authors.rb
        
      • で、こんなマイグレーションファイル(20111221221234_add_birth_to_authors.rb)が生成されるんだねー。
        class AddBirthToAuthors < ActiveRecord::Migration
         def change
           add_column :authors, :birth, :date
         end
        end
        
      • んー、やっぱり本とは違って、changeメソッドのみだねー。
      • んでもって、これは単に「基本」でしかないから、後は手作業で変更していくって感じだね。
  • マイグレーションファイルでは、いろんなメソッドがあるんだねー。
    add_column カラム追加
    add_index インデックス追加
    add_timestamps created_at/updated_atを追加
    change_column カラムを変更
    change_column_default カラムのデフォルト値を変更
    change_table テーブル変更
    column_exists? カラムが存在するかをチェック
    drop_table テーブルを削除
    index_exists? インデックスが存在するかをチェック
    remove_column カラム削除
    remove_index インデックス削除
    remove_timestamps created_at/updated_atを削除
    rename_column カラム名を変更
    rename_index インデックス名を変更
    rename_tbale テーブル名を変更
    execute SQLを実行
  • んでもって、マイグレーションの実行は、「rake」コマンドね。
    • 単に最新にするなら、「rake db:migrate」だけ
      C:\user\dev\railbook\app>rake db:migrate
      (in C:/user/dev/railbook)
      ==  AddBirthToAuthors: migrating ==============================================
      -- add_column(:authors, :billname, :string)
         -> 0.0000s
      ==  AddBirthToAuthors: migrated (0.0000s) =====================================
      
      • んー、なんか既にbirthカラムがあってエラーになっちゃったので、とりあえずカラム名だけ変えて動かしたけど…。
      • 良く見りゃ、初めのデータベースの準備でbirth入ってるね…。
    • 他にもいろいろできる
      rake db:rollback STEP=1 指定ステップまでバージョンを戻す
      rake db:migrate VERSION=20111221221234 指定バージョンまで移行
      rake db:migrate:redo STEP=5 指定ステップだけ戻して、再実行
      rake db:migrate:reset DBを削除後、スキーマ再作成
    • Railsは、データベースをテスト/本番とかが簡単に切り替え可能で、それはRAILS_ENVオプションで指定
      rake db:migrate RAILS_ENV=test
      
  • へー、スキーマファイル(db/schema.rb)は、マイグレーションのまとめファイルって感じなんだ!
    • 中身はこんな感じだね。
      ActiveRecord::Schema.define(:version => 20111124220655) do
      
       create_table "authors", :force => true do |t|
         t.integer  "user_id"
         t.string   "name"
         t.date     "birth"
         t.text     "address"
         t.string   "ctype"
         t.binary   "photo"
         t.datetime "created_at"
         t.datetime "updated_at"
       end
      
       add_index "authors", ["user_id"], :name => "index_authors_on_user_id"
       ---- 以下略 ---
      
    • 使い方は、こんな感じ
      • スキーマを展開するのは、schema:loadね
        rake db:schema:load
        
      • 再構築なら、reset
        rake db:reset
        
      • SQLスクリプト(db/development_structure.sql)を生成することもできるんだ
        rake db:structure:dump
        
    • db/schema.rb の再生成は、migrate:resetが良さそう。
      rake db:migrate:reset
      
      • rake db:reset だと、db/schema.rbを使ってのDB再構築みたいだな。
  • おおー、データ初期化用の仕組みが2つもあるんだ。
    • シードファイル(db/seeds.rb)はRubyコードで、マスターデータ登録用みたい
      • まあ、単にモデルを使ってデータを登録するんだねー。
      • seeds.rbは、こんな感じかな?
        # coding: utf-8
        Book.create(:id => 1, :isbn => '111-2-3333-4444-0', :title => '自分の本', :price => 100, :publish => '適当出版', :published => '2011-12-01', :cd => false)
        
      • で、db:seedでデータ投入する、と。
        rake db:seed
        
      • あー、db:setupでも自動で実行されるんだ
        C:\user\dev\railbook\app>rake db:setup
        (in C:/user/dev/railbook)
        db/test.sqlite3 already exists
        db/development.sqlite3 already exists
        -- create_table("authors", {:force=>true})
           -> 0.0312s
        ======= 以下略 ======
        
    • フィクスチャは、YAML or CSVのデータファイルで、テストデータ登録用かな?
      • test/fixtures/****.ymlにファイルを作るのねー。例えば「books.yml」の内容は、こんな感じ?
        mysql5:
          id: 1
          isbn: 978-4-7980-2812-5
          title: MySQL5逆引き大全460の極意
          price: 2730
          publish: 秀和システム
          published: 2010-12-01
          cd: false
        
      • 一行目は、ラベルなんだ!なんで、他でもラベルが使えるっぽい事が書いてあるけど…、駄目でした…。なんでじゃろ?
      • で、フィクスチャでのデータ登録は、こんなコマンドで実行
        rake db:fixtures:load FIXTURES=users,reviews,books
        
      • あー、db以下じゃなくてtestの方なんだ…。
      • おおっと、フィクスチャでは、テンプレートと同様にスクリプトブロックを書けるみたい。これは便利かも?

-
最終更新:2012年09月07日 06:28