Ruby on Rails-談Migration概念與用法

張凱喬
10 min readDec 25, 2017

--

在網路上看到了這張圖
可以讓在rails裡migration到迷路的朋友提供慰藉

在一開始學Rails時 一定經歷過
rails generate model user
rails db:migrate
然後根本搞不懂migration在搞屁

基本上migration並不代表資料庫

他只是一個「資料庫變更的紀錄檔」

這個記錄檔在生成時會自動產生戳記
你的資料庫每執行一次migration 都會紀錄戳記
所以資料庫會知道你執行過哪一個migration、哪個還沒

db:migrate 就是讓資料庫「執行還沒執行過的migration」
執行過的migration則會自動略過

本篇上半部會先列出常用的migration用法
下半部再介紹Rollback相關的概念與用法

上半部:常見用法

常用migration檔產生 有兩種來源
一種是generate model時自動產生(多用於初始化model)
一種是generate migration時產生(多用於修改資料庫結構)

※補充
產生migration有許多懶人法(幫你省下一兩行程式碼的時間)
譬如rails g migration RemoveNameFromMerchant name:string
他就會幫你在檔案裡面使用remove_column方法 並把name放進去

接下來是migration的語法
先列出比較常用的

create_table(name, options)#新增資料表
drop_table(name)#移除資料表
rename_table(old_name, new_name)#修改資料表的名稱
add_column(table, column, type, options) #新增欄位
rename_column(table, old_column_name, new_column_name)#修改欄位名稱
change_column(table, column, type, options)#修改欄位設定
remove_column(table, column)#移除欄位

舉例而言#1
如果要修改一個欄位名稱的話

rails g migration FixColumnName #輸入一個容易辨識的migration檔名

class FixColumnName < ActiveRecord::Migration
def change
rename_column :table_name, :old_column, :new_column
end #正常都會使用:symbol
end

舉例而言#2
如果要設定欄位的初始值

rails g migration add_default_value_to_columndef change
change_column :table_name, :column_name, :column_type, default: "default setting"
end

舉例而言#3
如果要把欄位設定為不可空白

rails g migration set_null_false_to_columndef change
change_column :table_name, :column_name, :column_type, null: false
end

※補充
這邊的null跟false都是option,詳見以下說明

Create table的範例請參考說明

就新手(我)而言
最常用的資料庫操作相關rails指令如下

rake db:migrate #執行Migration動作
rake db:rollback STEP=n #回復上N個 Migration 動作
rake db:seed #執行 db/seeds.rb 載入種子資料
rake db:version #目前資料庫的Migration版本
rake db:migrate:status #顯示目前 migrations 執行的情況

此外,還有一個重要的檔案 就是 db/schema.rb
這個檔案是根據Migrations遷移最後的結果,
自動產生出來的終極資料庫綱要檔案。

再看一下最上面那一個圖
migration其實就是資料庫的版本紀錄控制

每一次migrate之後的結構
就會存在schema(你也可以解讀為資料庫快照)

你也可以db:migrate:status 看一下現在做了什麼
如果有問題的話 就是rollback
但是rollback的概念有點混亂...下半部介紹

※補充
為什麼常常在指令中看到rake
因為rake是ruby的gem(rake = Ruby Make)
後來rails很多功能都使用Rake的功能了
後來就直接把rake指令名稱納進去rails
所以rake db:migrate 等於 rails db:migrate

下半部:RollBack

之所以要分上下部打
主要是這個rollback有點抽象
要先理解來龍去脈之後才比較有概念

以前在4.0之前migration檔都需要寫UP 與 DOWN
其實就是版本往上 跟 版本往下的意思

參考這一份rails 3的中文文件
舉例如下

class AddDetailsToProducts < ActiveRecord::Migration     def self.up     
add_column :products, :part_number, :string
add_column :products, :price, :decimal
end

def self.down
remove_column :products, :price
remove_column :products, :part_number
end
end

UP就是執行rake db:migrate時會幹的事情
DOWN就是執行rake db:rollback時會幹的事情

更詳細一點
rake db:migrate會把沒做過的migration up都執行一次
rake db:rollback只會執行最近一次的migration down

簡單來說
如果你的up是新增欄位 這樣down就是刪除欄位
但是如果你有一些特別需求(譬如處理關聯性)
則有可能up與down的內容是有一點不同的

rake db:rollback STEP=n #回復上N個 Migration 動作
rollback也可以指定要回復幾個動作

那你可能問說
如果像是寫def change這樣把內容包起來
沒有分up and down 這樣rails 怎麼執行版本的升降

Rails幫你整理出這些change Method
已經內含了up and down的功能
(也就是你寫up的動作,rails就能知道down作甚麼)

此外也可以指定要做哪一個版本的up 或 down
舉例來說

rake db:migrate:up VERSION=20080906120000

這會執行 20080906120000 這一版的 migration 的 up 方法。
db:migrate:up 和 db:migrate:down 會去確認這個 migration 目前有沒有跑過,所以,如果 Active Record 認為 20080906120000 已經跑過了,那麼執行 db:migrate:up VERSION=20080906120000 就不會做任何動作。

這些東西其實都是在學Rails後才慢慢了解
但其實是通用於資料庫操作的一些概念

這篇先這樣
繼續加油
ㄅㄅ

--

--

Responses (1)