在 ActiveAdmin 中显示复选框而不是文本输入

Show checkboxes instead of text input in ActiveAdmin

在模型 Code 中有一个名为 week_days 的字段,它可能是这样的 1100110。 我想在 ActiveAdmin 表单中显示 7 个复选框,而不是经典的输入字段

  form do |f|
    f.inputs do
      f.input :name
      f.input :week_days
    end
    f.actions
  end

所以我想在模型中写一个这样的映射器

  def week_days_checkboxes
    [
        ['sunday', 1],
        ['monday', 1],
        ['tuesday', 1],
        ['wednesday', 1],
        ['thursday', 1],
        ['friday', 1],
        ['saturday', 1]
    ]
  end

  def week_days_checkboxes=(week_days_checkboxes)
    @week_days = week_days_checkboxes.reverse.join.to_i(2)
  end

然后把表单输入改成这样

f.input :week_days_checkboxes, as: :check_boxes

但它不起作用。我必须做什么?

PS:每对的第二个值应为1或0,基于字段week_days

的每个值

非常感谢

由于以下几个原因它不起作用:

  1. 在 AR 模型中分配实例变量不会实现您想要的。您应该使用 self[:column_name]= valuewrite_attribute(:column_name, value) (我认为后者更能揭示意图)。对于阅读,您可以使用 self[:column_name]read_attribute 方法。
  2. 当您 post 带有复选框或多个 select 离子的表单时,只有 selected 值会被发送回服务器(浏览器就是这样工作的)。这意味着如果你只 select 一天,数组的值将永远是 ['', '1'],不管你是哪一天 select。在这种情况下,基本上使用统一值不是解决问题的方法。
  3. week_days_checkboxes 方法返回一个数组数组将不会显示选项列表,因为它表示 而不是选项。您必须明确设置集合。

    f.input :week_days, as: :check_boxes, collection: week_days_for_select
    

    其中 week_days_for_select return 是一个合适的列表。

    当您编辑现有模型时,先前 selected 的天数将不会 selected 在复选框列表中。为此,您需要 return 一个与复选框输入值匹配的值列表。

一个解决方案可能是:

在您看来:

f.input :week_days, as: :check_boxes, collection: Date::DAYNAMES

然后在您的模型中为 week_days 创建一个包装器,以便它接受一个列表并将其转换为整数,反之亦然。

def week_days
  return [] if read_attribute(:week_days).blank?

  # first you have to convert the integer to a binary array
  w = read_attribute(:week_days)
  days_as_binary = Math.log2(w).floor.downto(0).map { |nth_bit| w[nth_bit] }

  # alternatively
  # days_as_binary = read_attribute(:week_days).to_s(2).split('').map(&:to_i)

  # make sure it has an element for every day of the week
  padded_binary = [0] * (7 - days_as_binary.size) + days_as_binary

  # map the binary array to day names
  padded_binary.each_with_index.map do |d, idx|
    Date::DAYNAMES[idx] if d == 1
  end.compact
end

def week_days=(values)
  days = Date::DAYNAMES.map { |d| values.include?(d) ? 1 : 0 }
  write_attribute(:week_days, days.join.to_i(2))
end

尽管我认为将 selected 天数表示为整数并不是您的最佳选择。如果您使用的是 PostgreSQL,AR 4+ 对数组有很好的支持——您可以将天数列表保存到数据库中。