iT邦幫忙

2022 iThome 鐵人賽

DAY 25
0
Modern Web

Ruby新手村的礦工日記系列 第 25

[ Day 25 ] Rails : 聽說 Migration 是個狠角色?!

  • 分享至 

  • xImage
  •  

前幾章有介紹過如何透過 Model 建立你要的資料表以及要的欄位,也有提到 Migration 檔,也提到你需要將資料表具現化,也就是在終端機 rails db:mrigate,這一張就讓我們好好深入研究吧!

Migration 是?

Migration 檔是:

  • 主要用來描述「資料庫的架構長怎樣」。
  • 紀錄資料庫的建立與修改。
  • 會進到 Git 版本控制。

新增 Migration

以上一章 Book 的例子來看,我們透過 Model 產生了一個 Migration 檔,這個檔案是描述這個資料表的結構,如下:

class CreateBooks < ActiveRecord::Migration[6.1]
  def change
    create_table :books do |t|
      t.string :name
      t.text :content

      t.timestamps
    end
  end
end

上述的資訊確認無誤後,可以透過 rails db:migrate 來將這個描述檔具現化。
如果沒有執行這個指令的話,你會看到這樣的錯誤訊息:
未db:migrate
你可以選擇按 Run pending migrations 或執行 $ rails db:migrate ,這兩個方法是一樣的。

修改 Migration

如果執行完 Migrate 後,才發現欄位名字打錯,或是少開一個欄位,這時候該怎麼辦呢?
身為新手的我,下意識進到剛剛的 Migration 檔進行修改,存檔後再執行一次 $ rails db:migrate,這時發現根本沒有效果。
該怎麼做呢?別擔心,做法有好幾種:

  1. 使用 Rollback
  2. 新稱 Migration

Rollback

其中一個方法就是執行 rails db:rollback,當你執行後,會把執行過的 Migration 倒回去,就有點像時光機似的。
rollback
如果你要倒轉不只一個 Migration,假設你要一次倒轉 2 個,可以加上 STEP=2

$ rails db:rollback STEP=2

注意:
雖然使用 Rollback 可以退回去刪除資料表或刪除欄位,但如果原本就有資料了,請不要使用 Rollback 的方式去修正,我建議新增一個 Migration 來修正。

新增 Column

現在有 books 資料表,但是我想要加一個 price 的整數欄位:

$ rails g migration add_price_to_books

這邊可以看到他幫你建立了一個 Migration 檔:
新增 column
通常命名會是像以上這樣,你當然可以自己取名,但為了讓人一眼就知道這個 Migration 檔是做了什麼事,還是建議以上面這樣命名。
我們來看看這個檔案裡面有什麼:

class AddPriceToBooks < ActiveRecord::Migration[6.1]
  def change
  end
end

這邊只幫你產生一個空殼而已,所以我們要在這裡面新增想要的欄位:

class AddPriceToBooks < ActiveRecord::Migration[6.1]
  def change
    add_column :books, :price, :integer
  end
end

add_column 後面的第一個參數 (books) 是「資料表名稱」(不是 Model 名稱!),第二個參數 (price) 是「要新增的欄位名稱」,第三個參數 (integer) 是「資料型態」。
寫完之後要記得執行 $ rails db:migrate :
add_price

移除 column

如果可以新增,那個就可以移除,作法跟新增相似,但要將前面改成 remove_column
這次我想要移除 books 資料表中的 content 的欄位,如下:

$ rails g migration remove_content_to_books

之後會發生的事情,會跟新增的是一模一樣的,這邊就不再贅述了。
我們在裡面寫上想要移除的欄位名稱:

class RemoveContentToBooks < ActiveRecord::Migration[6.1]
  def change
    remove_column :books, :content, :text
  end
end

記得要執行 rails db:migrate ,執行完後:
remove_column

schema.rb 是什麼?

我們執行完 rails db:migrate 後,我們可以進到 db/schema.rb 來看:

ActiveRecord::Schema.define(version: 2022_10_10_113608) do

  create_table "books", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.integer "price"
  end

end

這些東西是執行 rails db:migrate 之後產生的,我們可以不定手動修改這個檔案。而這個檔案可以看出每個資料表的名稱、欄位名稱與型態,而這個檔案也會在 Git 版本控制中。

Migration 忘記存檔就執行了!

Migration 寫好但還沒存檔就執行會發生什麼事呢?
不會怎樣,只是執行了一個空的 Migration 而已。
在新手階段,有時候會忘記存檔就執行 rails db:migrate ,就會鬧出這樣的烏龍「奇怪,怎麼明明 Migration 檔裡就有寫這些欄位,但為什麼 schema.rb 裡卻沒有」,我建議每次寫完要記得存檔

查看 Migration 狀態

我們可以透過 rails db:migrate:status 查看 Migration 狀態,如下:
查看 Migration 狀態

  • up 這個 Migration 已執行過
  • down 這個 Migration 尚未執行

常見指令

這邊整理一些我常用的相關指令

  • 新增:rails g migration ...
  • 刪除:rails d migration ...
  • 移除整個資料庫:rails db:drop
  • 重新建立資料庫:rails db:create
  • 資料表具現化:rails db:migrate
  • 查看 Migration 狀態:rails db:migrate:status

參考資料:

  1. 為自己學 Ruby on Rails
  2. Rails Guides

上一篇
[ Day 24 ] Rails 中的 Model 基本與 CRUD (下)
下一篇
[ Day 26 ] Rails : Model 的關聯性(一對一)
系列文
Ruby新手村的礦工日記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
yojijun
iT邦新手 4 級 ‧ 2022-10-11 14:58:31

剩五天!!!!!

我要留言

立即登入留言