Lưu enum từ select trong Rails 4.1


108

Tôi đang sử dụng enums trong Rails 4.1 để theo dõi màu sắc của rượu.

Wine.rb

class Wine < ActiveRecord::Base
    enum color: [:red, :white, :sparkling]
end

Theo quan điểm của tôi, tôi tạo một lựa chọn để người dùng có thể chọn một loại rượu có màu nhất định

f.input :color, :as => :select, :collection => Wine.colors

Điều này tạo ra HTML sau:

<select id="wine_color" name="wine[color]">
  <option value=""></option>
  <option value="0">red</option>
  <option value="1">white</option>
  <option value="2">sparkling</option>
</select>

Tuy nhiên, khi gửi biểu mẫu, tôi nhận được lỗi đối số nêu rõ '1' is not a valid color. Tôi nhận ra điều này là bởi vì colorphải bằng 1và không"1" .

Có cách nào để buộc Rails giải thích màu dưới dạng số nguyên chứ không phải là chuỗi không?

Câu trả lời:


203

Được rồi, rõ ràng là bạn không nên gửi giá trị số nguyên của enum sẽ được lưu. Bạn nên gửi giá trị văn bản của enum.

Tôi đã thay đổi đầu vào thành như sau:

f.input :color, :as => :select, :collection => Wine.colors.keys.to_a

Điều gì đã tạo ra HTML sau:

<select id="wine_color" name="wine[color]">
  <option value=""></option>
  <option value="red">red</option>
  <option value="white">white</option>
  <option value="sparkling">sparkling</option>
</select>

Các giá trị đã tăng từ "0" thành "đỏ" và bây giờ chúng ta đã hoàn tất.


Nếu bạn đang sử dụng text_field ol 'rails thông thường thì đó là:

f.select :color, Wine.colors.keys.to_a


Nếu bạn muốn có các thuộc tính rõ ràng mà con người có thể đọc được, bạn cũng có thể làm:

f.select :color, Wine.colors.keys.map { |w| [w.humanize, w] }


8
FWIW, tôi cần phải thực hiện nó f.select :color, Wine.colors.to_a.map { |w| [w[0].humanize, w[0]] }wđại diện cho một mảng. Không chắc tại sao, nhưng có thể điều này sẽ giúp ích cho ai đó.
jakealbaugh

sử dụng titleizecó thể là một ý tưởng tốt hơn nếu bạn có hai hoặc nhiều từ
Anwar

8
các keysphương thức trả về một mảng nên to_alà không cần thiết. Ngoài ra, phương pháp select helper lấy một mảng 2D cho các tùy chọn để bạn có thể sử dụng to_a.
xander-miller

Điều gì sẽ xảy ra nếu một Chuỗi không hợp lệ được gửi, chẳng hạn như "ERROR_JUNK_Submission". Rõ ràng là không có giá trị enum như giá trị này, và một ngoại lệ được ném ra. Chúng ta sẽ bắt nó ở đâu?
FlyingV

Mô hình Rượu vang có một màu sắc được gọi là enum enum color: [:red, :white, :sparkling]nên câu đúng làf.input :color, :as => :select, :collection => Wine.color.keys.to_a
hguzman Ngày

32

Không cần chuyển đổi enum băm thành mảng với to_a. Điều này đủ:

f.select :color, Wine.colors.map { |key, value| [key.humanize, key] }

10

Tôi vừa tập hợp một EnumHelper mà tôi nghĩ rằng tôi sẽ chia sẻ để giúp những người cần thêm nhãn và ngôn ngữ enum tùy chỉnh cho các lựa chọn enum của bạn.

module EnumHelper

  def options_for_enum(object, enum)
    options = enums_to_translated_options_array(object.class.name, enum.to_s)
    options_for_select(options, object.send(enum))
  end

  def enums_to_translated_options_array(klass, enum)
    klass.classify.safe_constantize.send(enum.pluralize).map {
        |key, value| [I18n.t("activerecord.enums.#{klass.underscore}.#{enum}.#{key}"), key]
    }
  end

end

Ở ngôn ngữ của bạn:

 en:
   activerecord:
     enums:
      wine:
        color:
          red:   "Red Wine"
          white:  "White Wine"

Theo quan điểm của bạn:

 <%= f.select(:color, options_for_enum(@wine, :color)) %>

1
Tóm lược sửa đổi làm cho các phím dịch dễ đọc hơn bằng cách tìm enums thuộc MultipleWordClassName dưới multiple_word_class_name khá điển hình hơn là multiplewordclassname
Tetsujin không Oni

Làm thế nào về việc thêm trong một mặc định cho một dự phòng duyên dáng: [I18n.t("activerecord.enums.#{klass.underscore}.#{enum}.#{key}", default: key.humanize), key] Ngoài ra, loại bỏ cuối cùng humanizevì nó có thể làm sai lệch giá trị vốn nếu nhiều từ nó
Peter P.

9

Giải pháp được chấp nhận không hoạt động đối với tôi đối với con người có thể đọc được , nhưng tôi có thể làm cho nó hoạt động như thế này:

<%= f.select(:color, Wine.colors.keys.map {|key| [key.humanize, key]}) %>

Đây là cái sạch nhất, nhưng tôi thực sự cần phải nhân hóa các chìa khóa của mình:

<%= f.select(:color, Wine.colors.keys) %>

1
ray 5 hỗ trợ cách sạch tại
V-SHY

@ V-SHY, cách này là gì, bạn có thể giải thích được không?
ismailarilik

2
@ismailarilik, cung cấp trực tiếp các khóa dưới dạng tùy chọn đã chọn, <% = f.select (: color, Wine.colors.keys)%>
V-SHY

6

Nếu bạn sử dụng enum trong Rails 4 thì chỉ cần gọi Model.enums:

f.select :color, Wine.colors.keys

Để tạo HTML:

<select name="f[color]" id="f_color">
    <option value="red">red</option>
    <option value="white">white</option>
    <option value="sparkling"> sparkling </option>
</select>

Hoặc thêm phương thức trong bộ điều khiển:

def update_or_create
    change_enum_to_i
    ....
end

def change_enum_to_i
    params[:f]["color"] = params[:f]["color"].to_i
end

4

Đây là những gì đã làm việc cho tôi, Rails 4+:

class Contract < ApplicationRecord

enum status: { active:  "active", 
               ended: "active", 
               on_hold: "on_hold", 
               terminated:  "terminated", 
               under_review:  "under_review" , 
               unknown: "unknown" 
              }


end

trong my _form.html.erb, tôi có cái này:

  <div class="field">
    <%= form.select :status, Contract.statuses.keys, {}%>
  </div>

kiểm tra từ Bảng điều khiển sau khi thêm bản ghi:

2.3.0 :001 > Contract.last.status
  Contract Load (0.2ms)  SELECT  "contracts".* FROM "contracts" ORDER BY "contracts"."id" DESC LIMIT ?  [["LIMIT", 1]]
 => "active"

3

Nếu bạn cần xử lý i18n dựa trên các khóa enum, bạn có thể sử dụng:

<%= f.select :color, Wine.colors.keys.map {|key| [t("wine.#{key}"), key]} %>

và trong tranlations, bạn có thể đặt màu:

wine:
 red: Red
 white: White

1

Đây là giải pháp của tôi (các vai trò của tôi có dấu gạch dưới như "sales_rep") và vì lý do nào đó, đây là cách tôi cần để tùy chọn trống hoạt động (với biểu mẫu đơn giản?):

Trong ứng dụngHelper:

def enum_collection_for_select(attribute, include_blank = true)
  x = attribute.map { |r| [r[0].titleize, r[0]] }
  x.insert(0,['', '']) if include_blank == true
  x
end

Sau đó ở dạng của tôi:

<%= f.input :role, collection: enum_collection_for_select(User.roles), selected: @user.role %>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.