2011-11-16 30 views
15

Tôi hiện có mô hình Tham dự sẽ có cột trạng thái và cột trạng thái này sẽ chỉ có một vài giá trị cho cột đó. STATUS_OPTIONS = {: vâng,: không,: có thể}Làm cách nào để chỉ định và xác thực enum trong đường ray?

1) Tôi không chắc chắn làm cách nào tôi có thể xác thực điều này trước khi người dùng chèn Tham dự? Về cơ bản một enum trong java nhưng làm thế nào tôi có thể làm điều này trong đường ray?

+0

mu và câu trả lời của mike là tốt - xem thêm http://stackoverflow.com/q/265725/887124, mang đến cho một số câu trả lời hơi khác nhau cho một câu hỏi tương tự. –

+0

Vâng, tôi thực sự sử dụng một cái gì đó tương tự như giải pháp mà Bob đã cung cấp: [gist] (https://gist.github.com/1372650) – mnelson

Trả lời

26

Tạo một mảng truy cập trên toàn cầu trong những lựa chọn mà bạn muốn, sau đó xác nhận giá trị của cột trạng thái của bạn:

class Attend < ActiveRecord::Base 

    STATUS_OPTIONS = %w(yes no maybe) 

    validates :status, :inclusion => {:in => STATUS_OPTIONS} 

end 

sau đó, bạn có thể truy cập vào các trạng thái có thể qua Attend::STATUS_OPTIONS

+5

Pre Rails 4.1 điều này là tốt. Trong Rails 4.1+ sử dụng được xây dựng trong enums: http://edgeguides.rubyonrails.org/4_1_release_notes.html#active-record-enums – mnelson

+1

Sử dụng "enums" bản địa trong đường ray 4.1 có cùng một nhược điểm của việc sử dụng enums thực sự bản địa trong postgresql. Bạn cần phải quan tâm đến thứ tự thực tế, bạn không thể dễ dàng sửa đổi enum một khi được tạo ra vv. Hơn nữa, với enums "native" rails, đó là một tính năng bị hỏng, bởi vì trên một mặt bạn viết và đọc chúng như stings, nhưng trên phía bên kia bạn cần truy vấn chúng dưới dạng số. Ít nhất với enums của postgresql, mọi thứ trong cơ sở dữ liệu sẽ thấy chuỗi. – rewritten

+0

Sau khi đấu tranh trong một giờ cố gắng để có được công việc enum, giải pháp này là thú vị hơn nhiều, và không có nhược điểm - không thể nói tương tự cho Enum. –

4

Bạn có thể sử dụng một cột chuỗi cho tình trạng và sau đó là :inclusion option for validates để chắc chắn rằng bạn chỉ nhận được những gì bạn đang mong đợi:

class Attend < ActiveRecord::Base 
    validates :size, :inclusion => { :in => %w{yes no maybe} } 
    #... 
end 
45

Bây giờ Rails 4.1 bao gồm enums bạn có thể làm như sau:

class Attend < ActiveRecord::Base 
    enum size: [:yes, :no, :maybe] 
    # also can use the %i() syntax for an array of symbols: 
    # %i(yes no maybe) 
    validates :size, inclusion: { in: sizes.keys } 
end 

Mà sau đó cung cấp cho bạn với một phạm vi (ví dụ: Attend.yes, Attend.no, Attend.maybe cho mỗi một phương pháp kiểm tra để xem nếu tình trạng nhất định được thiết lập (ví dụ: #yes?, #no?, #maybe?), cùng với các phương thức setter thuộc tính (ví dụ: #yes!, #no!, #maybe!).

Rails Docs on enums

+4

Từ những gì tôi đọc đường ray thực hiện hiện tại của enums là cho giá trị nội bộ và không cho tiếp xúc với người dùng như câu hỏi (mà tôi nghĩ là một sự xấu hổ). Tôi nhận được điều này từ chủ đề sau đây từ ngày 14 tháng 2 https://github.com/rails/rails/issues/13971 –

+2

Yêu thích nó. Thực hành tốt nhất mới, imo. –

2

gì chúng tôi đã bắt đầu làm là xác định mục enum chúng tôi trong vòng một mảng và sau đó sử dụng mảng để xác định enum, kiểm chứng thực, và sử dụng các giá trị bên trong ứng dụng.

STATUS_OPTIONS = [:yes, :no, :maybe] 
enum status_option: STATUS_OPTIONS 
validates :status_option, inclusion: { in: STATUS_OPTIONS.map {|t| t.to_s } } 

Bằng cách này bạn cũng có thể sử dụng STATUS_OPTIONS sau, như để tạo danh sách thả xuống. Nếu bạn muốn để lộ giá trị của bạn để người dùng mà bạn luôn có thể lập bản đồ như thế này:

STATUS_OPTIONS.map {|s| s.to_s.titleize } 
0

Đối với enums trong ActiveModels bạn có thể sử dụng đá quý này Enumerize

8

Đây là cách tôi thực hiện trong Rails của tôi 4 dự án.

class Attend < ActiveRecord::Base 
    enum size: [:yes, :no, :maybe] 
    validates :size, inclusion: { in: Attend.sizes.keys } 
end 

Attend.sizes cung cấp cho bạn ánh xạ.

Attend.sizes # {"yes" => 0, "no" => 1, "maybe" => 2} 

See more in Rails doc

+6

Về cơ bản cùng một nhận xét như [this one] (http://stackoverflow.com/questions/8146965/how-do-i-specify-and-validate-an-enum-in-rails/8147002#comment42094863_26365696), nhưng điều này sẽ không hoạt động, vì các thuộc tính enum sẽ ném một ngoại lệ InvalidArgument lên các giá trị không hợp lệ, trước khi xác thực được gọi. Thông tin thêm về điều đó tại đây: https://github.com/rails/rails/issues/13971 –

+0

@Koen. là đúng tôi đã thử giải pháp này và kết thúc với 'ArgumentError' bất kể. –

0

Sau khi một số tìm kiếm, tôi không thể tìm thấy một lớp lót trong mô hình để giúp cho nó xảy ra. Hiện tại, Rails cung cấp Enums, nhưng không phải là một cách toàn diện để xác nhận hợp lệ các giá trị không hợp lệ.

Vì vậy, tôi đã chọn giải pháp tổng hợp: Để thêm xác thực trong bộ điều khiển, trước khi đặt strong_params và sau đó bằng cách kiểm tra mô hình.

Vì vậy, trong mô hình, tôi sẽ tạo ra một thuộc tính và xác nhận tùy chỉnh:

tham dự.rb

enum :status => { your set of values } 
attr_accessor :invalid_status 

validate :valid_status 
#... 
private 
    def valid_status 
     if self.invalid_status == true 
      errors.add(:status, "is not valid") 
     end 
    end 

Ngoài ra, tôi sẽ làm một kiểm tra đối với các thông số cho đầu vào không hợp lệ và gửi kết quả (nếu cần) để mô hình, vì vậy một lỗi sẽ được bổ sung vào đối tượng, do đó làm cho nó không hợp lệ

attends_controller.rb

private 
    def attend_params 
     #modify strong_params to include the additional check 
     if params[:attend][:status].in?(Attend.statuses.keys << nil) # to also allow nil input 
      # Leave this as it was before the check 
      params.require(:attend).permit(....) 
     else 
      params[:attend][:invalid_status] = true 
      # remove the 'status' attribute to avoid the exception and 
      # inject the attribute to the params to force invalid instance 
      params.require(:attend).permit(...., :invalid_status) 
     end 
    end 
Các vấn đề liên quan