Reputation: 43
I have 0 experience with jsonb, so apologies if this is a basic question. I managed to get my dynamic form built and submit to the database, but I would like to change the format that the data is getting to the database. I'm using Postgres and my "status" field is jsonb.
With my form design its storing the data like:
{
"9" => "23",
"11" => "1",
"13" => "1",
"14" => "1",
"18" => "32"
}
I would like the data to be stored in the following maner:
[
{
id: "9"
value: "23"
},
{
id: "13"
value: "23"
}
]
My Model:
class Client < ApplicationRecord
extend FriendlyId
friendly_id :name, use: :slugged
validates :name, presence: true, uniqueness: true
belongs_to :country
belongs_to :client_unit, optional: true
belongs_to :industry, optional: true
end
My form:
<div class="row">
<% schema = JSON.parse @client.schema %>
<%= form_for @client, url: {action: "update"} do |f| %>
<%= f.fields_for :status, OpenStruct.new(@client.status) do |df| %>
<% schema.each do |initiative| %>
<div class="card card-block col-6">
<div class='card-header bg-primary text-light'>
<h5><%= initiative['name'] %></h5>
<small> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. <i class="fas fa-sm fa-info-circle"></i> </small>
</div>
<div class='card-body'>
<div class='form-group'>
<% initiative['milestones'].each do |milestone| %>
<% if milestone['category'] == 'Boolean' %>
<div class='custom-control custom-checkbox pt-2' style='padding-left: -30px; padding-bottom: 0px'>
<%= df.check_box milestone["id"], class: 'custom-control-input', include_hidden: false%>
<%= df.label milestone['id'], milestone['name'], class: 'custom-control-label' %>
<%= check_box_tag 'status[value]', true %> ###### <-- This is me trying stuff out
</div>
<% else %>
<div class='input-group input-group-sm pt-2'>
<%= df.text_field milestone["id"], class: 'form-control', style: 'max-width: 45px' %>
<label class="control-label" style="padding-left: 10px; padding-top: 3px"><%= milestone['name'] %></label>
</div>
<% end %>
<small style="padding-bottom: 10px;"> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. <i class="fas fa-sm fa-info-circle text-primary"></i> </small>
<% end %>
</div>
</div>
</div>
<% end %>
<% end %>
<div class='card-footer'>
<%= button_to :submit %>
</div>
<% end %>
</div>
Upvotes: 0
Views: 232
Reputation: 102055
To pass arrays in Rails (and Rack in general) as formdata you want to use empty brackets in the keys:
irb(main):019:0> qs = "client[milestones][][id]=9&client[milestones][][value]=23&client[milestones][][id]=13&client[milestones][][value]=23"
irb(main):020:0> p = Rack::Utils.parse_nested_query(qs)
=> {"client"=>{"milestones"=>[{"id"=>"9", "value"=>"23"}, {"id"=>"13", "value"=>"23"}]}}
You can use fields_for
to setup nested inputs possibly by using a struct as the model. I'm not really sure what to actually make of that form as there is way to much insanity going on. In absolutely no situation should you be doing stuff like JSON parsing in the view.
I have a strong feeling you're missing some key domain objects.
To whitelist an array of hashes pass a hash key with an array of permitted attributes:
irb(main):005:0> params = ActionController::Parameters.new({"client"=>{"mileston
es"=>[{"id"=>"9", "value"=>"23", "id\n "=>"13"}, {"value"=>"23"}]}})
irb(main):006:0> params.require(:client).permit(:foo, :bar, milestones: [:id, :v
alue])
=> <ActionController::Parameters {"milestones"=>[<ActionController::Parameters {"id"=>"9", "value"=>"23"} permitted: true>, <ActionController::Parameters {"value"=>"23"} permitted: true>]} permitted: true>
Upvotes: 1