2013年6月26日 星期三

Rails的db:seed小技巧

在開發Rails專案時,在db的sync上,常常會遇到下面兩個情況:

1. 開發環境與正式環境的初始資料
2. 多人開發時的local DB同步問題

第二個問題其實只要開一個遠端的伺服器來共用就解決了,但是在使用sqlite或是沒有網路的情況下,這麼做實在很麻煩,而且有時候我們也不希望別人的資料弄髒資料庫。這時候我們可以使用seed.rb來初始化資料庫中的資料,我們來看看怎麼做:
# seed.rb

areas = [
  {name:"台北"},
  {name:"高雄"}
]
Area.create areas
然後下rake db:seed這個指令就行了


進階需求


但是需要初始化的資料往往都是系統的固定選項(如縣市等不應被隨意增加、減少的資料),這時常常會有需要指定id的需求,這時我們就要稍微修改一下作法:
areas = [
  {id:1, name:"台北"},
  {id:2, name:"高雄"}
]
areas.each do |area|
  s = Area.new area
  s.id = area[:id]
  s.save
end

如果是確定此資料表中只會出現seed中所寫入的資料的話,我們可以加上delete_all來先清空資料表再做插入資料的動作:
Area.delete_all

使用csv匯入資料


在只有少量資料需要被處理時,直接將資料寫在seed.rb十分方便,但是當資料量很大時,我們希望能以報表的形式事先整理好再做匯入。而csv是一個格式簡單,也能被Excel, Numbers等報表軟體支援的檔案格式,因此我選擇它作為外部資料匯入的媒介。

但是在Excel中比較難去設定成我們想要的utf-8編碼,比較建議使用Apple的Numbers軟體,可以直接輸出成utf-8的csv檔。

來一段簡單的程式碼大家應該就能看懂了:
# seed.rb

require "csv"
SysSchool.delete_all
CSV.foreach("#{Rails.root}/db/school.csv") do |row|
 school = {
  id:row[0],
  name:row[1],
  sys_area_id:row[2]
 }
 s = SysSchool.new school
 s.id = school[:id]
 s.save
end

這段程式碼也是要貼在seed.rb中的,這樣一來在執行"rake db:seed"時,就會先刪除資料表中的資料,並將db/school.csv裡的資料一列一列插進資料表中。