在 Active Record 裡,有一個滿常見的功能,Enum,這功能該如何使用,今天就來點 Enum 吧!
Enum 是什麼?
Enum(Enumeration的縮寫)稱為列舉,是一種程式設計中常見的資料型別,
用於定義一組具有固定名稱的整數常數。
這些名稱通常用作代表特定狀態、選項、或類別的符號,使我們在程式上更易於閱讀、理解和維護。
讓我們來看看 Rails 裡該如何使用 Enum 吧!
Enum in Ruby on Rails
在 Rails 中,Enum(列舉)是一個用於定義 Model 屬性的機制。
可以使用 Enum 來將整數映射到易於理解的名稱(自定義名稱),以增強代碼的可讀性。
首先,我們已經建立好 Order
Model,
現在我想針對一張訂單可能會有的狀態新增一個欄位到 orders
資料表上。
一張訂單可能有這四種狀態:pending
、shipped
、delivered
和 canceled
,
可以在建立狀態欄位上使用整數的資料型態來設置:
1 | rails g migration AddStatusToOrder status:integer |
點進去剛剛新增的 migration 檔案:
1 | class AddStatusToOrder < ActiveRecord::Migration[7.0] |
如果想設定預設值為 0
,可以加上 default: 0
1 | class AddStatusToOrder < ActiveRecord::Migration[7.0] |
如何在 Model 定義 Enum?
接著,我們到 Order
Model,使用 Enum 來定義狀態:
在定義上可以使用多種方式,來看看有哪些寫法吧!
Array
1
2
3
4# app/models/order.rb
class Order < ApplicationRecord
enum :status, [:pending, :shipped, :delivered, :canceled]
end%i()
format1
2
3
4# app/models/order.rb
class Order < ApplicationRecord
enum :status, %i(pending shipped delivered canceled)
end當我們使用陣列的方式去定義時,
pending
、shipped
、delivered
和canceled
,
將會被映射到0
、1
、2
和3
(陣列的第一個元素 index 為 0,以此類推)。Hash
除了使用 Array,我們還可以使用 Hash 去設定,並為每個值自定義整數或名稱去對應:1
2
3
4
5
6
7
8
9# app/models/order.rb
class Order < ApplicationRecord
enum :status, {
pending: 0,
shipped: 1,
delivered: 2,
canceled: 3
}
end1
2
3
4
5
6
7
8
9# app/models/order.rb
class Order < ApplicationRecord
enum :status, {
pending: '待處理',
shipped: '已發貨',
delivered: '已送達',
canceled: '已取消'
}
end在使用上,比較建議用 Hash 的方式去定義,
因為當使用 Array 定義 Enum 時,資料庫會存取相應的 index 值,當之後要更改現有 Enum 的順序上會導致問題,因為資料庫裡的值可能與新的順序不符。
因此,當使用 Hash 定義,因為是自定義值,不是依賴於 index 值。當要更改 Enum 的順序時,只需更新 Enum 的 Hash 自定義值,而不會影響現有資料的整合性。
Enum 在 Rails 如使用?
在 Model 定義好 Enum 之後,我們要如何使用呢?
Order Model 擁有新的方法了!
透過複數型來抓取整個定義好的狀態 - 使用 statuses
方法
透過剛剛的 Hash 定義,我們便可以用 Order.statuses
得到一個 Hash 如下:
1 | # app/models/order.rb |
1 | Order.statuses |
查詢具有相應狀態的訂單記錄 - 使用 pending
, shipped
, delivered
, canceled
方法
透過 Order.pending
, Order.shipped
, Order.delivered
, Order.canceled
,
這些方法用於查詢具有相應狀態的訂單記錄。Order.pending
將返回所有狀態為 “pending” 的訂單。
1 | Order.pending |
透過建立一張新的 order - 使用 status
方法
status
方法是一個可以用在知道一個實體變數的狀態方法:
建立一張新的 order001 之後,可以用 order001.status
,
剛剛因為有設定 default: 0
,所以結果會是 “pending”。
1 | order001 = Order.create(order_name: "20231010001") |
確認 order 狀態 - 使用 pending?
, shipped?
, delivered?
, canceled?
方法
透過自定義的名稱加上 ?
,可以檢查是否為某種狀態:
1 | order001 = Order.create(order_name: "20231010001") |
更新 order 狀態 - 使用 pending!
, shipped!
, delivered!
, canceled!
方法
透過自定義的名稱加上 !
,可以更新狀態:
1 | order001 = Order.create(order_name: "20231010001") |
1 | order001.shipped? |
另外,我們也可以使用:order001.update(status: :shipped)
1 | order001.update(status: :shipped) |
1 | order001.shipped? |
但是相較 !
,這寫法比較冗長,我比較想要快速一點點,通常我都會用第一種方式去更新!
prefix, suffix
在 Enum 還可以使用 prefix
和 suffix
選項來控制生成的方法的前綴和後綴,以避免命名衝突。
prefix(前綴):
1
2
3class Order < ApplicationRecord
enum status: { pending: 0, shipped: 1, delivered: 2, canceled: 3 }, prefix: true
end生成的方法將具有前綴
status_
:status_pending
、status_shipped
、status_delivered
、status_canceled
。suffix(後綴):
1
2
3class Order < ApplicationRecord
enum status: { pending: 0, shipped: 1, delivered: 2, canceled: 3 }, suffix: true
end生成的方法將具有後綴
_status
:pending_status
、shipped_status
、delivered_status
、canceled_status
。
今天就到這啦!我們下篇見~
參考資料:
➫ Active Record Query Interface #Enums
➫ How to Use Enums in Rails
➫ How to use enum attributes in Ruby on Rails