Rails Migration 資料庫變動的利器
喜歡作者的文章嗎?馬上按「關注」,當作者發佈新文章時,思書™就會 email 通知您。
思書是公開的寫作平台,創新的多筆名寫作方式,能用不同的筆名探索不同的寫作內容,無限寫作創意,如果您喜歡寫作分享,一定要來試試! 《 加入思書》
思書™是自由寫作平台,本文為作者之個人意見。
給本文個喜歡
或不
關於作者
很久以前就是個「寫程式的」,其實,什麼程式都不熟⋯⋯
就,這會一點點,那會一點點⋯⋯
看看作者的其他文章
看看思書的其他文章
如果問我當初為什麼選擇用 Rails 開發後台,Rails 的 Migration 絕對是一個重要的原因,我很喜歡這個設計,清楚簡單又好用,當然啦,我後來對其他後台開發平台也沒有深入研究,也許其他的也很厲害,但是選了後就用到現在,沒有怨言。
這篇文章是 Migration 的使用流程、重點與一些特殊用法的記錄,如果要全面性的了解,還是要看以下的 Rails 指南的:Active Record Migrations,另外高見龍的文章也很生動有趣,很值得一看:Model Migration | 高見龍。
什麼是 Rails migration ~ 就是讓 Rails 更新資料庫啦
我的 Migration 標準流程
我所有的開發文件上,只要有用到 Migration 都會有以下的註記,也就是我的標準作業流程:
所以,可以很清楚的看到我的流程就是以下的幾個步驟:
rake db:migrate
,如果有錯,就改,如果執行順利,但是又發現不對,可以用 rollback 回到 migration 前的資料庫狀態我很喜歡各種 Rails 的自動產生器,如果要新增一個資料表,我會用 rails g scaffold,這樣一次到齊所有 MVP,所以我幾乎不會用到 migration 來新增資料表,大部分都是用在新增與刪除資料欄位,我想這也是大家會使用 migration 的地方。
以下是每一個點的一些使用細節。
註記資料庫修改說明與目的
這個我覺得是最重要的,相信我,資料庫的新增與修改當下都很清楚,但是一段時間後,保證全部忘光光,如果沒有清楚的文件記錄,往往就要花很多的時間來閱讀舊的程式碼,但是大家不要忘了,Rails 的程式碼可是分散在各處的,一個資料欄位的使用可以是在 Model 裡,也可以是在 controller 或是 view 裡面,重新閱讀程式碼是一件很痛苦的事,而且一定會有遺漏,最好的方法就是清楚的文件記錄,我建議的資料庫註記方式如下,註記在兩個地方:
精萃版註記:
特別是未來開發程式要注意的地方,就把簡潔關鍵的說明放在 migration 程式裡,Rails 5 以前要用 migration_comments 或是其他的 gem,Rails 5 以後就可以直接加在 migration 裡了,你只要在 migration 的欄位中加入
comment:
就好,例如:t.integer :block_type, comment: '0-no block, 1-block by user, 2-block by customer, any other is no blocking'
這種用法只支援 mySQL 跟 PostgreSQL,有點可惜,加上後,就可以在 schema.rb 中看到這些精萃版的註記,非常的方便查詢,聽說 MySQL Workbench 跟 PgAdmin III 也可以讀到,我沒用就是了。
理由與思緒:
紀錄當初選擇這樣做的原因,特別是為什麼不用其他方式的理由,把它寫在 model 的頭,或是開發文件裡,選一個地方放就好,不要兩個地方都寫,不同步更亂。 理由與思緒的過程是很重要的,如果沒有詳細的紀錄,一是太可惜了,二是忘記了後,一碰到問題,又要再想一遍。
用 Rails 的自動 Migration 產生器
我看好多人都喜歡自已寫,我好怪,我就是喜歡用自動 Migration 產生器,我覺得電腦會寫最好,自己寫好容易出錯,而且電腦好快,以下是 Migration 產生器的常用方法:
references 跟 belongs_to 是一樣的東西,選一個你喜歡的用。
加入預設
有兩種預設,一是資料欄位的預設,另一個是要讀取別的 Model。
資料欄位加入預定(modifiers)及 index
一下是一些常用的 Migration 程式修改點:
:text, default: ""
:integer, :default => 0
:boolean, default: true
:datetime, default: -> {'CURRENT_TIMESTAMP'}
:date, :default => nil
:decimal, precision: 5, scale: 2
:null => true
:comment
t.belongs_to :column, foreign_key: true
t.references :column, foreign_key: true
add_index :table, :column, :unique => true
刪除 timestamp
欄位的預設值來自別的 Model
有時,你會想要新增一個 column,它的值是來自另外一個相關聯的 table,雖然這樣做有違背資料庫的一致性,但是可能是為了速度或是其他理由,這時,你的 migration 程式內就會需要新增一個讀取功能,基本上,migration 程式就是一個 ruby 程式,所以,就是加一段 ruby 進去。
我們來看這個 migration 例子,我們要在書本的 table 中新增一個語言別欄位,它的值來自作者:
這是一個用 up/down 的方法,我想大家一定注意到,change 被改成 up/down 了,是的,這是為了要讓 rollback 能運做,大家可以想想,新增時 migration 程式中會讀取資料寫入新增的欄位,如果 rollback 也這樣做,一定死掉。
另一個不同是增加了
Book.reset_column_information
,這基本就是將 table 重讀,確定等待欄位新增成功。class Book < ActiveRecord::Base; end
有點爭議性,將新增的 model 關聯methods/callback/validation 完全暫停好嗎?這真的要看需要了,一般來說,新增的資料必須要與舊的資料關聯一致,這樣做有風險,自己做判斷吧。更新資料就是執行一段 ruby / rails 程式碼,你可以讀取任何 active records 或是運算,甚至執行 SQL,很方便的,注意一下資料更新的時間,migration 本來就不快。
我喜歡改用 up/down 這個老方法的方法,但是如果你堅持,你可以續用 change,這時就要將更新資料的程式碼用 reversible 包起來,如下:
兩個都差不多啦,自取所好。
執行 Migration
不要怕,小心就好,Migration 程式如果寫錯了,一執行,就會出現錯誤,改到對就好,執行後,如果查看 schema.rb 有誤,就給他 rake db:rollback,當資料庫越來越大時,執行起來真的很有壓力,特別是要設定預設值時,又很慢,我的建議是,一次增加少少的欄位就好,仔細地在開發環境下好好的測試,特別是 validation 部分,一定要確定無誤後,才可以上傳到 production site,畢竟,如果客戶資料被搞掉了,那就問題太大了,上傳前務必要再三測試確認,真的不要急。
這篇文章沒有寫到一大堆更深入的 migration 用法,例如:增加刪除 foreign/index keys,改變 default,join_table,create table 等等,也沒提到種子資料的建立,這些部分就請看 rails guide 吧,我還不熟,不敢亂寫。
BTW,rails 5 以後都是用 rails db:xxx 了,我還在寫 rake db:xxx,大家別介意啦,就用習慣了。
就這樣,希望對大家有幫助。