使用 Rails 和 Postgresql 在 jsonb 字段中存储数组数据

Storing array data in jsonb field with Rails and Postgresql

假设我有一个汽车模型,我想在其中显示不同类型的数据。我将 data 列添加到 table:

class AddDataToCars < ActiveRecord::Migration[5.0]
  def change
    add_column :cars, :data, :jsonb, null: false, default: '{}'
    add_index  :cars, :data, using: :gin
  end
end

然后我为我想要出现的字段添加一个访问器 (extra_options):

class Car < ApplicationRecord
  store_accessor :data, :wheel_count, :extra_options

  validates :extra_options, presence: true
end

我确保它是 cars_controller.rb 中允许的参数:

def car_params
  params.require(:car).permit(:make, :model, :data, :wheel_count, :extra_options)
end

现在我可以在我的 _form.html.erb 部分中创建一个文本输入,将数据放入 wheel_count 中,如下所示:

<div class="field">
  <%= f.label :wheel_count %>
  <%= f.text_field :wheel_count %>
</div>

它按预期工作。然后我想要的是 select 列表(多个 select)或一组复选框,其中 selected 选项存储在 extra_options.

我试过:

<%= f.select :extra_options, options_for_select(["1", "2", "3", "4", "5"], car.extra_options), { include_blank: true }, { multiple: true } %>

产生了以下标记:

<input name="car[extra_options][]" type="hidden" value="" />     
<select multiple="multiple" name="car[extra_options][]" id="car_extra_options">
  <option value=""></option>
  <option value="1">1</option>
  <option value="2">2</option>
  <option value="3">3</option>
  <option value="4">4</option>
  <option value="5">5</option>
</select>

显然,选项标签应该比 1、2、3、4 和 5 更有意义,但更糟糕的是,当我提交表单时,什么都没有存储。

如果我 select 2 和 3 提交,参数如下所示:

"extra_options"=>["", "2", "3"]

这会导致消息 Unpermitted parameter: extra_options,所以似乎不允许我在此字段中放置数组。

仅仅为了一些额外的选项而创建一个 jsonb 字段似乎很愚蠢,但它自然也会保存各种其他数据。

那么我如何创建多个 select 列表或最好是一组复选框,以便在 jsonb 字段中正确保存数据(当然,在编辑提交时显示已经 selected/checked 的项目)?

试试这个,在 car_params

params.require(:car).permit(:make, :model, :data, :wheel_count, extra_options: [])

对于复选框,试试这个

    <%= hidden_field_tag "car[extra_options][]", [] %>
    <% ["1", "2", "3", "4", "5"].each do |o| %>
      <% default_checked = car.extra_options.include?(o.to_s) rescue false %>
      <label class="rightpad">
        <%= check_box_tag "car[extra_options][]", o, default_checked %>
      </label>
      <span>
        <%= o %>
      </span>
    <% end %>