12/08/2018, 11:53

Sử dụng enum trong ruby on rails

Enum là gì? Enum là kiểu dữ liệu liệt kê, giúp bạn tổ chức dữ liệu khoa học hơn, code được trong sáng dễ hiểu hơn. Khi khai báo một thuộc tính kiểu enum, bạn có thể lưu dữ liệu vào database theo kiểu integer nhưng có thể truy vấn theo tên. Ví dụ: class Conversation < ...

Enum là gì?

  • Enum là kiểu dữ liệu liệt kê, giúp bạn tổ chức dữ liệu khoa học hơn, code được trong sáng dễ hiểu hơn.
  • Khi khai báo một thuộc tính kiểu enum, bạn có thể lưu dữ liệu vào database theo kiểu integer nhưng có thể truy vấn theo tên. Ví dụ:
class Conversation < ActiveRecord::Base
      enum status: [:active, :archived]
end
# conversation.update! status: 0
conversation.active!
conversation.active? # => true
conversation.status  # => "active"
# conversation.update! status: 1
conversation.archived!
conversation.archived? # => true
conversation.status    # => "archived"
# conversation.status = 1
conversation.status = "archived"
conversation.status = nil
conversation.status.nil? # => true
conversation.status      # => nil

Sử dụng enum như thế nào?

  • Khai báo đơn giản. Ví dụ:
class Conversation < ActiveRecord::Base
      enum status: [:active, :archived]
end
  • Hỗ trợ các scope dựa trên các giá trị. Ví dụ:
Conversation.active
Conversation.archived

Tất nhiên, bạn vẫn có thể truy vấn trực tiếp nếu scope không phù hợp với nhu cầu của bạn.

Conversation.where(status: [:active, :archived])
Conversation.where.not(status: :active)
  • Bạn có thể đặt giá trị mặc định cho thuộc tính khi tạo database:
create_table :conversations do |t|
      t.column :status, :integer, default: 0
end

Tốt nhất là đặt giá trị đầu tiên của thuộc tính làm giá trị mặc định.

  • Cuối cùng, bạn cũng có thể đặt tên và giá trị của thuộc tính kiểu enum theo ý muốn một cách rõ ràng bằng cách sử dụng một Hash. Ví dụ:
class Conversation < ActiveRecord::Base
      enum status: {active: 0, archived: 1}
end

Lưu ý

  • Khi sử dụng Array, các giá trị được lưu trữ trong database là thứ tự các giá trị xuất hiện trong mảng. Ví dụ, :active sẽ được lưu là 0 vì nó là phần tử đầu tiên, và :archived sẽ được lưu là 1. Tổng quát, các phần tử thứ i sẽ được lưu là i-1 trong database.
    Vì vậy, khi một giá trị được thêm vào mảng enum, vị trí của nó trong mảng phải được duy trì cố định và các giá trị mới chỉ nên được thêm vào cuối mảng. Để loại bỏ các giá trị không cần thiết, nên sử dụng cú pháp Hash rõ ràng.
    Trong một số trường hợp, có thể bạn cần phải lấy ra các giá trị integer trong database. Các giá trị này sẽ được lấy ra thông qua một class method với tên là số nhiều của thuộc tính, và trả về mảng giá trị trong một HashWithIndifferentAccess:
Conversation.statuses[:active]    # => 0
Conversation.statuses["archived"] # => 1

Sử dụng class method này khi bạn cần biết giá trị thực sự của thuộc tính được lưu trong database. Ví dụ, bạn có thể sử dụng khi tạo một query SQL:

Conversation.where("status <> ?", Conversation.statuses[:archived])
  • Bạn có thể sử dụng tùy chọn :_prefix hoặc :_suffix khi cần khai báo nhiều enum với các giá trị giống nhau. Nếu giá trị truyền vào là đúng, các method của enum sẽ được thêm vào các tiền tố/hậu tố tương ứng. Ngoài ra, bạn cũng có thể cung cấp một giá trị khác cho :_prefix/:_suffix
class Conversation < ActiveRecord::Base
  enum status: [:active, :archived], _suffix: true
  enum comments_status: [:active, :inactive], _prefix: :comments
end

Với các ví dụ trên, bạn có thể sử dụng các method và scope với tiền tố và hậu tố như mong muốn:

conversation.active_status!
conversation.archived_status? # => false
conversation.comments_inactive!
conversation.comments_active? # => false
0