在 Rails 的開發流程,我們會使用 rails g model post
產生所需要的 model 檔案。這個指令會在 app/model/
下產生 post.rb,這是 model 檔案。此指令另外也會在 db/migration/
下產生 (time_stamp)_create_post.rb
,這是連帶產生的 db migration 檔。
在傳統的 web application 開發流程中,並不存在 db migration 機制。開發者多半使用 phpmyadmin 開設所需要的 db 欄位。
db migration 檔的格式如下:
class CreatePosts < ActiveRecord::Migration
def self.up
create_table :posts do |t|
t.string :title
t.text :excerpt
t.text :content
t.timestamps
end
end
def self.down
drop_table :posts
end
end
Rails 開發者將所需要開設的欄位加進 migration 檔案,執行 rake db:migrate
,即可完成新增資料庫以及資料欄位的新增。
同樣的,若要對資料庫欄位進行更動,也是一樣透過 migration。rails g migration add_user_id_to_post
會產生一個空 migration 檔,再將所需變更寫入檔案,再次執行 rake db:migrate
即可:
class AddUserIdToPost < ActiveRecord::Migration
def change
add_column :users, :user_id, :integer
end
end
由其他語言剛轉換過來的開發者,對於這樣的設計通常會感覺到不習慣。透過 phyMyAdmin 就可以進行的操作,為什麼要繞了一個圈?透過 rake 和 migration 對資料庫進行操作。
在傳統開發流程中,當一個人獨自進行開發且未進行至部署階段時,開發者都不會感覺到有什麼問題。
但若專案陸續加入了第二位、第三位開發者,就會陷入極大的麻煩:沒有人知道現在的 db schema 長成什麼樣子。當 A 決定將 post 的 title 改成 subject 時,僅透過 phyMyAdmin 改變了 db schema,而忘了告訴 B,就將 code push 到了程式版本控制系統。而 B 根本不曉得了這一個變更,於是 B 的開發端就爆炸了,這樣的事件層出不窮。
若沒有使用 db migration 機制,在佈署時開發者必須要自己手動輸入 SQL 或透過 phpMyAdmin 變更資料欄位。而這樣的動作在程式碼與 production 環境且 db schema 差異過大時,是非常危險的:
DB schema 難道是不可能被版本控制的嗎? Rails 解決了這樣的難題:db migration 正是因此誕生的的 best practices。
透過 db migration 檔,可以紀錄資料庫每一次的欄位變遷,並且可以被版本控制。而協同開發者,在 checkout 程式碼下來之後,看到欄位發生變更,只要執行 rake db:migration
就可以追上資料庫最新的進度。
同時,rake db:migrate
的動作是全自動化的,如果在開發端能夠執行,在 production 環境上也可以重製。而 db migration 檔也提供了回復的機制,如果程式碼哪邊出現了問題,導致對應的資料庫欄位可能也要暫時改回去,只要執行 rake db:rollback
就可以回復到上一次變更前的狀態。