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

时间:2015-01-23 16:16:48

标签: ruby-on-rails activeadmin formtastic

在模型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:根据字段week_days

的每个值,每对的第二个值应为1或0

非常感谢

1 个答案:

答案 0 :(得分:5)

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

  1. 在AR模型中分配实例变量无法达到您想要的效果。你应该使用self[:column_name]= valuewrite_attribute(:column_name, value)(我认为后者更有意图揭示)。要阅读,您可以使用self[:column_name]read_attribute方法。
  2. 当您发布带有复选框或多个选择的表单时,只会将选定的值发送回服务器(这是浏览器的工作方式)。这意味着,如果您只选择一天,则无论您选择哪一天,数组的值始终为['', '1']。在这种情况下,基本上不使用统一值。
  3. week_days_checkboxes方法返回数组数组将不会显示选项列表,因为它表示而不是选项。您必须明确设置集合。

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

    week_days_for_select返回适当的列表。

    当您编辑现有模型时,不会在复选框列表中选择之前选择的日期。为此,您需要返回与复选框输入相匹配的值列表。值。

  4. 一种解决方案可能是:

    在您看来:

    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
    

    虽然我认为将所选天数表示为整数并不是您的最佳选择。如果您使用的是PostgreSQL,AR 4+可以很好地支持数组 - 您可以将数据列表保存到数据库中。