Ruby on Rails form with array of nested hashes - ruby-on-rails

I'm trying to build a rails form to submit an array of nested hashes.
In controller i want to get params in structure like:
[
{
id: 'section1',
rows:
[
{ id: '1', seats: '1-20' },
{ id: '2', seats: '1-25' }
]
},
{
id: 'section2',
rows:
[
{ id: '1', seats: '1-50' },
...
]
},
...
]
It's not a problem to dynamically add additional sections and rows fields with js, but i cant figure out how this form should look like to work properly.

Related

How to create loop within a JSON request object?

I need to create multiple "items" to be used within a json request .
Here's a request that works:
customs_info = EasyPost::CustomsInfo.create(
eel_pfc: 'NOEEI 30.37(a)',
customs_certify: true,
customs_signer: "first_name last_name",
contents_type: 'merchandise',
contents_explanation: '',
restriction_type: 'none',
restriction_comments: '',
# non_delivery_option: 'abandon',
customs_items: [
{
description: "asdf",
quantity: 1,
weight: 23,
value: 23,
# hs_tariff_number: '654321',
origin_country: 'US'
},
{
description: "1234568",
quantity: 1,
weight: 23,
value: 23,
# hs_tariff_number: '654321',
origin_country: 'US'
}
]
)
What I need is to not need to manually set the customs_items.
I tried:
customs_info = EasyPost::CustomsInfo.create(
eel_pfc: 'NOEEI 30.37(a)',
customs_certify: true,
customs_signer: "#{shipping_address.shipping_address_final.first_name} #{shipping_address.shipping_address_final.last_name}",
contents_type: 'merchandise',
contents_explanation: '',
restriction_type: 'none',
restriction_comments: '',
# non_delivery_option: 'abandon',
customs_items: [
vendor_line_items.map do |li|
{
description: "#{li.shop_product.product.item.title}",
quantity: li.quantity,
weight: li.shop_product.product.weight,
value: li.shop_product.price,
# hs_tariff_number: '654321',
origin_country: 'US'
}
end
]
)
Error Statement: Parameters to create Custom Item(s) invalid or missing
How can I create the loop to work with the JSON request and work like the first example that works manually?
If you remove the [] that is surrounding the vendor_line_itmes.map code, you will be good to go.
customs_info = EasyPost::CustomsInfo.create(
# ...
customs_items: vendor_line_items.map do |li|
{
description: "#{li.shop_product.product.item.title}",
quantity: li.quantity,
# ...
}
end
)
The map operation returns an array so the json you are currently generating would look like (note the array of arrays in customs_info):
{
"eel_pfc": "NOEEI 30.37(a)",
...
"customs_info": [
[
{
"description": "...",
"quantity": 5,
...
}
]
]
}

Create a deep nested hash using loops in Ruby

I want to create a nested hash using four values type, name, year, value. ie, key of the first hash will be type, value will be another hash with key name, then value of that one will be another hash with key year and value as value.
The array of objects I'm iterating looks like this:
elements = [
{
year: '2018',
items: [
{
name: 'name1',
value: 'value1',
type: 'type1',
},
{
name: 'name2',
value: 'value2',
type: 'type2',
},
]
},
{
year: '2019',
items: [
{
name: 'name3',
value: 'value3',
type: 'type2',
},
{
name: 'name4',
value: 'value4',
type: 'type1',
},
]
}
]
And I'm getting all values together using two loops like this:
elements.each do |element|
year = element.year
element.items.each |item|
name = item.name
value = item.value
type = item.type
# TODO: create nested hash
end
end
Expected output is like this:
{
"type1" => {
"name1" => {
"2018" => "value1"
},
"name4" => {
"2019" => "value4"
}
},
"type2" => {
"name2" => {
"2018" => "value2"
},
"name3" => {
"2019" => "value3"
}
}
}
I tried out some methods but it doesn't seems to work out as expected. How can I do this?
elements.each_with_object({}) { |g,h| g[:items].each { |f|
h.update(f[:type]=>{ f[:name]=>{ g[:year]=>f[:value] } }) { |_,o,n| o.merge(n) } } }
#=> {"type1"=>{"name1"=>{"2018"=>"value1"}, "name4"=>{"2019"=>"value4"}},
# "type2"=>{"name2"=>{"2018"=>"value2"}, "name3"=>{"2019"=>"value3"}}}
This uses the form of Hash#update (aka merge!) that employs a block (here { |_,o,n| o.merge(n) } to determine the values of keys that are present in both hashes being merged. See the doc for definitions of the three block variables (here _, o and n). Note that in performing o.merge(n) o and n will have no common keys, so a block is not needed for that operation.
Assuming you want to preserve the references (unlike in your desired output,) here you go:
elements = [
{
year: '2018',
items: [
{name: 'name1', value: 'value1', type: 'type1'},
{name: 'name2', value: 'value2', type: 'type2'}
]
},
{
year: '2019',
items: [
{name: 'name3', value: 'value3', type: 'type2'},
{name: 'name4', value: 'value4', type: 'type1'}
]
}
]
Just iterate over everything and reduce into the hash. On the structures of known shape is’s a trivial task:
elements.each_with_object(
Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) } # for deep bury
) do |h, acc|
h[:items].each do |item|
acc[item[:type]][item[:name]][h[:year]] = item[:value]
end
end
#⇒ {"type1"=>{"name1"=>{"2018"=>"value1"},
# "name4"=>{"2019"=>"value4"}},
# "type2"=>{"name2"=>{"2018"=>"value2"},
# "name3"=>{"2019"=>"value3"}}}

Nested/Sub Tables with PDFMake

How do I use nested/sub tables with PDFmake? I've tried simply putting in multiple tables but that doesn't automatically repeat the top level table's header for page breaks.
This code is a simplified example of using a sub-table. It is adapted from tables section of the pdfmake playground (wasn't easy to find via Google searching).
Paste the following into: http://pdfmake.org/playground.html
// playground requires you to assign document definition to a variable called dd
var dd = {
content: [
{ text: 'A simple table with nested elements', style: 'subheader' },
'It is of course possible to nest any other type of nodes available in pdfmake inside table cells',
{
style: 'tableExample',
table: {
headerRows: 1,
body: [
['Column 1', 'Column 2'],
[
{
stack: [
'Let\'s try an unordered list',
{
ul: [
'item 1',
'item 2'
]
}
]
},
[
'or a nested table',
{
table: {
body: [
[ 'Col1', 'Col2', 'Col3'],
[ '1', '2', '3'],
[ '1', '2', '3']
]
},
}
]
]
]
}
},
]
}
I need to achieve almost similar functionality like above. I have tried a lot, but not getting it right. How to create a json array that would produce an pdf output using pdfmake? I need to create a table within a table:
var dd = {
content: [
{
text: 'A simple table with nested elements',
style: 'subheader'
},
'It is of course possible to nest any other type of nodes available in pdfmake inside table cells',
{
style: 'tableExample',
table: {
headerRows: 1,
body: [
['Column 1', 'Column 2'],
[
[
'or a nested table',
{
table: {
body: [
[ 'Col1', 'Col2', 'Col3'],
[ '1', '2', '3'],
[ '1', '2', '3']
]
},
}
]
]
]
}
},
]
}

Best way to reformat json in Rails?

An app I am building receives some information in JSON, however the data is very poorly organized. I would like to rebuild the JSON output. The JSON I'm receiving is completely flat, and certain things should be nested. To illustrate what I mean:
I'm getting something like this:
{[
{fullname: 'Joe', session: 'A', time: '5:00', room: 'Ballroom'},
{fullname: 'Abe', session: 'B', time: '5:00', room: 'Bathroom'},
{fullname: 'Mike', session: 'C', time: '6:00', room: 'Bathroom'},
]}
I want something like this:
{
rooms: [
{
name: 'Ballroom',
sessions: [
{
title: 'A',
speakers: [{name: 'Joe'}]
}
]
},
{
name: 'Bathroom',
sessions: [
{
title: 'B',
speakers: [{name: 'Abe'}]
},
{
title: 'C',
speakers : [{name: 'Mike'}]
}
]
}
]
}
Are there any gems that are well equipped for doing something like this? Is there a specific part of the application this manipulation should be done in to follow MVC?
I should note that all this app does is receive this JSON and then makes API calls to another application to create/update information in that app's DB to reflect what's in the JSON.
Use:
JSON.pretty_generate your_hash
For example:
require 'json'
my_json = { :array => [1, 2, 3, { :sample => "hash"} ], :foo => "bar" }
puts JSON.pretty_generate(my_json)
refer to: How can I "pretty" format my JSON output in Ruby on Rails?
You can re-format using jbuilder or rabl gems. Usage and examples are pretty strait forward in their readme

Render RABL template with two objects

I recently came across a condition were i wanted to send two objects in the RABL as a response.
[
{
id: "1",
name: "XYZ"
},
{
id: "1",
name: "XYZ"
},
{
total: "2"
}
]
All I could manage was this , which is not correct.
[
{
id: "1",
name: "XYZ",
total: "2"
},
{
id: "1",
name: "XYZ",
total: "2"
}
]
I Found a solution which was to use a partial to iterate on the object and just add a new
node(:name) {partial("users/names", :object => #users)}
node(:total){ #total}
This is a hack, which i don't want because it wraps all the names in a node .
Is there any other way to do it ?
In your rabl file try this:
child #users, object_root: false do
attributes :id, :name
end
node(:total) { #users.size }

Resources