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

ald*_*dis 5 enums ruby-on-rails formtastic activeadmin

我正在使用 ActiveAdmin 来管理大型数据库,并且我的模型之一 (ItemType) 具有 ENUM 属性 (ItemType.units),并且我能够使用 Formtastic 呈现选择框和单选按钮,如下所示:

f.input :unit, :as => :radio, :collection => ItemType.units, include_blank: false
Run Code Online (Sandbox Code Playgroud)

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

class ItemType < ActiveRecord::Base
  enum unit: [ :Packages, :Pieces, :KG ]
end
Run Code Online (Sandbox Code Playgroud)

创建新资源时这可以正常工作,但使用表单编辑同一资源时不会检索该值。


这是数据库记录的默认“单一视图”:

独特的观点

这是同一记录的默认“编辑视图”。请注意如何没有选择任何值:

编辑视图

tmi*_*hel 4

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

ItemType.units #=> { "Packages" => 0, "Pieces" => 1, "KG" => 2 }
Run Code Online (Sandbox Code Playgroud)

当您将它用作无线电输入的集合时,它会将输入的值设置为 0、1、2 等。该值与返回值不匹配ItemType#unit(因为它将返回枚举的字符串表示形式,例如作为"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
Run Code Online (Sandbox Code Playgroud)

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

解决方案实际上非常简单。仅使用映射中的键:

f.input :unit, :as => :radio, :collection => ItemType.units.keys
Run Code Online (Sandbox Code Playgroud)

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

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

更好的选择是使用预定义的字符串数组并验证该值是否在预定义值列表中。大致意思是:

class ItemType
  UNITS = %w[kg packages pieces]
  validates :unit, inclusion: { in: UNITS }
end
Run Code Online (Sandbox Code Playgroud)