ActiveAdmin 和 Formtastic:使用 ENUM 显示单选按钮和 select 框的值

ActiveAdmin and Formtastic: Displaying the value for radio buttons and select boxes using ENUM

我正在使用 ActiveAdmin 管理一个大型数据库,我的一个模型 (ItemType) 有一个 ENUM 属性 (ItemType.units),我可以使用 Formtastic 来渲染一个 select 框和像这样的单选按钮:

f.input :unit, :as => :radio, :collection => ItemType.units, include_blank: false

ENUM 字段在模型中的定义如下:

class ItemType < ActiveRecord::Base
  enum unit: [ :Packages, :Pieces, :KG ]
end

这在创建新资源时工作正常,但在使用表单编辑同一资源时未检索到该值。


这里是数据库记录的默认 "singular view":

这里是同一条记录的默认 "edit view"。请注意 none 的值是如何 selected:

我会使用常量而不是枚举:

class ItemType < ActiveRecord::Base
  UNIT_VALUES = %w{Packages Pieces KG}
end

f.input :units, :as => :radio, :collection => ItemType::UNIT_VALUES, include_blank: false

当您声明一个枚举然后访问映射时,它return是一个散列:

ItemType.units #=> { "Packages" => 0, "Pieces" => 1, "KG" => 2 }

当您将它用作无线电输入的集合时,它会将输入的值设置为 0、1、2 等。该值与 [=14 的 return 值不匹配=](因为它将 return 枚举的字符串表示形式,例如 "KG")。

Rails 只能在列表中的值之一与属性值匹配时设置所选值。这种情况永远不会发生。

这种二元性(字符串与整数)将导致另一个痛点。您实际上无法保存表单,因为您只能将枚举的值设置为允许的值之一(字符串或整数表示形式)。

it = ItemType.new
it.unit = "KG" # this works
it.unit = :KG  # this works as well
it.unit = 1    # this works but WTF?!
it.unit = "1"  # this will raise an ArgumentError

由于表单参数被解析为字符串,ActiveAdmin 将尝试将 "1" 分配给 ItemType#unit,但它会失败。

解决方法其实很简单。仅使用映射中的键:

f.input :unit, :as => :radio, :collection => ItemType.units.keys

不过,如果可以的话,您应该远离使用 AR 的枚举。几个原因:

  • 它代表一个有意义的字符串和一个无意义的数字(这意味着如果没有应用程序代码,单位列中的数据将没有任何意义)
  • 它将应用程序的源代码与数据紧密耦合(很难在其他应​​用程序(例如数据库控制台)中单独使用数据)
  • 必须保持枚举值的顺序(或者必须提供显式映射)。它们都不是开发人员友好的。

使用预定义的字符串数组并验证该值是否在预定义值列表中是更好的替代方法。沿线的东西:

class ItemType
  UNITS = %w[kg packages pieces]
  validates :unit, inclusion: { in: UNITS }
end