來自 Ruby china 精華帖
关于在 Rails Model 中使用 Enum (枚举) 的若干总结
在我使用 enum 時東找西找,挖掘一些坑
裡面提到枚舉這個詞,就是指 enum
看到該篇內容很精闢,提到很多想整理的重點
所以也筆記一份,至於詳情大家可以去看該篇文章
Enum 就是 Rails 用來消滅魔鬼數字的工具。
代碼中,以數字方式去表示數據狀態,導致代碼可讀性被破壞,這樣的數字被稱為『 魔鬼數字 』。
官方說明 enum:
Declare an enum attribute where the values map to integers in the database, but can be queried by name.
給數據庫中的整型字段聲明一個一一對應的 enum(枚舉) 屬性值,可以使用該字面作為查詢。字面
ActiveRecord::Enum 與 Mysql 的 Enum 有何不同
Enum 是為了解決數據庫問題,當然數據庫本身也有該功能:
Mysql 為例子:
1 | CREATE TABLE person( |
這樣就設置了 gender
的 enum 字段
1 | { |
ActiveRecord::Enum 在實現上,並不直接使用數據自身的 enum,僅用普通的 Integer 来做存儲。避免了 enum 屬性變動時會修改數據庫結構的問題。
ActiveRecord::Enum 的使用
1 | # Migration |
聲明之後,會多出以下一些輔助方法:
1 | conversation.active! # 改寫狀態為 active |
使用注意事項
不要使用數據庫的 enum
不要使用數組預設定義 enum
1
enum status: %i[active waiting archived]
enum 字段赋值時,會做數據驗證
enum 的字面量要注意避开 model 已有的 method_names/attribute_names
建議给 enum 字段添加默认值
1
2
3create_table :conversations do |t|
t.integer :status, limit: 2, default: 0, null: false
end建議添加新属性时,寫 migration
- 檢測當前數據庫中新加的值是否已经被佔用
- 更新數據庫字段的 comment
1
2
3
4
5
6class AddDeletedStatusToConversations < ActiveRecord::Migration[5.1]
def up
raise "The value of deleted status has already been taken." if Conversation.deleted.count.positive?
change_column :conversations, :status, :integer, default: 0, null: false, comment: "0 - active, 1 - waiting, 2 - archived, 3 - deleted"
end
end建議數據庫字段不一定非得是 Integer
- 我的認為是沒特殊需求,以 integer 主佳
结合 I18n 做出多語系
請升级到 Rails 5 以上的版本
注意手動設置 table_name 並做關連查詢,會有的坑,是 Rails 5.x 的專屬問題
ActiveRecord::Enum 在 Rails 5.0+ 中的新特性
主要的改進有:
- where 查詢支持使用字面量做查詢條件
- conversation[:status] 與 conversation.status 返回值一致,都是字面量
- 增加了兩个可選參數 _prefix 和 _suffix