惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
阮一峰的网络日志
阮一峰的网络日志
A
About on SuperTechFans
大猫的无限游戏
大猫的无限游戏
Engineering at Meta
Engineering at Meta
V
Visual Studio Blog
Martin Fowler
Martin Fowler
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - 叶小钗
I
InfoQ
B
Blog RSS Feed
aimingoo的专栏
aimingoo的专栏
Y
Y Combinator Blog
Blog — PlanetScale
Blog — PlanetScale
IT之家
IT之家
P
Proofpoint News Feed
WordPress大学
WordPress大学
小众软件
小众软件
B
Blog
MongoDB | Blog
MongoDB | Blog
人人都是产品经理
人人都是产品经理
量子位
Hugging Face - Blog
Hugging Face - Blog
月光博客
月光博客

Nic Lin's Blog

謝明真 - 高效領導力的課後筆記 NFT 開發實戰!基礎智能合約入門 (3) NFT 開發實戰!基礎智能合約入門 (2) NFT 開發實戰!基礎智能合約入門 (1) 如何自我檢測 log4j CVE 漏洞 Rails 如何在資料寫入時記錄來源 IP 位置 如何經營工程師 Youtube 頻道 - Part 8 營收篇 如何經營工程師 Youtube 頻道 - Part 7 酸民文化篇 如何經營工程師 Youtube 頻道 - Part 5 設備器材篇 如何經營工程師 Youtube 頻道 - Part 4 後製剪輯篇 如何經營工程師 Youtube 頻道 - Part 3 文案企劃篇 如何經營工程師 Youtube 頻道 - Part 2 設備器材篇 如何經營工程師 Youtube 頻道 - Part 1 制訂頻道方向篇 如何經營工程師 Youtube 頻道 - Part 0 Rails 中避免 race condition 的最佳實踐(二) Rails 中避免 race condition 的最佳實踐(一) 10 分鐘整合 google sheet 做自動化開發功能週報 經營 Side Project 300 天所帶來的收穫及挑戰 我的 Youtube 影片製作流程 API 設計時必須注意的 HTTP header 底線問題 如何提升你的程式可讀性之實務技巧(三) 如何提升你的程式可讀性之實務技巧(二) 如何提升你的程式可讀性之實務技巧(一) Ruby 中使用 freeze 優化效能的時機 避免 React 中的 useEffect 無限 render 在 Rails 內輕量使用 Vue Component 的最佳實踐 如何在區域網路用 Docker 架設有 SSL 的 Gitlab 從被問到問人,那些我常問的面試問題 [Rails] 如何漂亮寫出可維護的 query (Maintainable Rails Query) 在已知長度情況下優化 slice 的性能
使用 AvtiveRecord:Enum 建立易讀的狀態屬性
Nic Lin · 2017-07-30 · via Nic Lin's Blog

在 Rails model 裡面,我們很常會定義所謂數據的「狀態」,比方說一個請假系統,光請假這個數據,可能他的狀態就有「待審核」、「已審核」、「已退回」、「已取消」。

雖然 Mysql 裡面也有 Enum 屬性可以設置,例如

CREATE TABLE person(
    name VARCHAR(255),
    gender ENUM('Male', 'Female')
);

既然一般資料庫都有 enum 屬性可以用,那為何我們很少知道有人這樣開發,其最大的問題在於這個 enum 會在建立這張表單時就塵埃落定,一旦後期需要增加一個狀態就意味著要在加一個字段,而且各類型的數據庫對於 enum 的方式處理不盡相同,會對 ORM 造成不小的麻煩,而 Rails 就除去了這個麻煩,讓數據庫只要單純的儲存 integer,並在 model 中來維護這些關係,並不直接使用數據庫的 enum,

在該 model 裡面,我們可以使用Constant(常數)去定義一個狀態的初始值

class LeaveEvent < ApplicationRecord
  STATUS = %i(pending approved rejected canceled).freeze
end

然後在 migration 生成數據時,切記狀態 default 值一定要設定「pending」

class CreateLeaveEvents < ActiveRecord::Migration[5.0]
  def change
    create_table :leave_events do |t|
      ...
      t.string :status, default: "pending"
      ...
    end
  end
end

這樣的作法是多數人在設定狀態會有的寫法,不過 Rails 在 4.1 的部分就針對了這樣常見的設定做了一個更棒的設置

ActiveRecord::Enum 的 Module

官方说明:

Declare an enum attribute where the values map to integers in the database, but can be queried by name.

如此一來,就可以用 enum 解決這個狀態設置的場景,更棒的是在資料庫裡面只需要儲存 integer 可以取代原本的 string

By the way 數據欄位型別也是會影響速度

Boolean > Integer > String > Date > Datetime

以請假系統來說,我們可以如此應用 Enum, 詳細參見官方文檔

先在 model 裡面宣告

class LeaveEvent < ActiveRecord::Base
  enum status: { pending: 0, approved: 1 ,rejected: 2, canceled: 3 }
  # or
  enum status: [ :pending, :approved, :rejected, :canceled ]
end

宣告後,會幫你生出這些方法

leave_event.approved! # 將狀態改寫為 approved
leave_event.approved? # 檢查該狀態是否 approved

leave_event.status     # => "approved" 輸出 String
leave_event[:status]   # => "approved" 輸出 String(Rails 5 Feature)

leave_event.status = 1            # => "approved"
leave_event.status = 'approved'   # => "approved"
leave_event.status = :approved    # => "approved" 
賦值時,以上三者等價

# 自動添加 Scope
LeaveEvent.approved    # 等價於 LeaveEvent.where(status: 1)

# 自動添加 statuses(status 的複數) 的 Hash
LeaveEvent.statuses # => { "pending" => 0, "approved" => 1, "rejected" => 2, "canceled" => 3 }

這邊值得注意的一點是,通常這些狀態設定,幾乎都不會更動順序,一旦更動順序可能就會導致災難發生

比方說

# 原先定義的順序
enum status: [:temporary, :active, :deleted]
# 修改之後
enum status: [:temporary, :active, :waiting, :deleted]
# 如果這樣修改的話,以前的 deleted 的數據修改後就變成 waiting了

而且上述的例子中,容易讓人混淆順序,所以並不推薦使用

enum status: [:temporary, :active, :deleted]

而建議有良心的寫 code

{ temporary: 1, active: 2, deleted: 3 }

也因為 enum 會自帶一些 scope ,這部份也要注意有沒有與原先自己設定的 scope 衝突,像是如果使用 enum status: { none: 0, active: 1, deleted: 2}

那麼 Rails 自帶的 none 就會被覆蓋了哦

參考資源 - Creating Easy, Readable Attributes With ActiveRecord Enums - 译:使用ActiveRecord Enums创建简单易读的属性 - Rails 关于在 Rails Model 中使用 Enum (枚举) 的若干总结