Rails Backbone Render Nested JSON in jst.eco template - ruby-on-rails

I have this set JSON data
JSON
[{
"country": {
"name": "Malaysia",
"total_amount": 0.0,
"count": 0
}
}, {
"country": {
"name": "Philippines",
"total_amount": 0.0,
"count": 0
}
}, {
"country": {
"name": "Thailand",
"total_amount": 0.0,
"count": 0
}
}]
Let say this data I sent it like
.replaceWith(#template(data: #data_transaction)
How do I retrieve the data inside the template.jst.eco
I have tried to use this kind of for loop
<% for key, data in #data_transaction.models: %>
<%= data.get("country").name %>
<%= data.get("country").total_amount %>
<%= data.get("country").count %>
it just does not work
if I tried to print it out this way inside the template.jst.eco
<%= #data_transaction %>
it will show this kind of things
[object, object]
Any helps?
Thank you very much

I fear you made a very common mistake.
Try to replace:
for key, data in #data_transaction.models:
with:
for object in #data_transaction.models:
for key, data of object:

Related

display nested JSON in ruby on rails

I believe this is going to be an easy fix but everything I'm trying isn't working.
I'm getting data from an external API and I'm looking at display the data after matching the ids.
The data is JSON and has some nested content.
I've tried the following
<li>Street: <%= #users.find{|u| u['id'] == #album['userId']}.try(:[],'address''street') || 'not available' %></li>
The data is structured like so
{
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere#april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
}
You'll want that to be:
<li>Street: <%= #users.find{|u| u['id'] == #album['userId']}.try(:[],'address').try(:[],'street') || 'not available' %></li>
For a multi-level try, you might want to look into dig.
Also, if the iteration is as in your previous questions, then #album may need to be album. If this is in a different context than your previous questions, then kindly disregard.
This is where dig is useful:
https://ruby-doc.org/core-2.3.0_preview1/Hash.html
<li>Street: <%= #users.find{|u| u['id'] == #album['userId']}.dig(:address, :street) || 'not available' %></li>

Rails 5: How do I loop over a hash with each do

I want to get a specific output from the Typeform API.
This is the response I get back.
Example response:
"answers": [
{
"field": {
"id": "hVONkQcnSNRj",
"type": "dropdown",
"ref": "my_custom_dropdown_reference"
},
"type": "text",
"text": "Job opportunities"
},
{
"field": {
"id": "RUqkXSeXBXSd",
"type": "yes_no",
"ref": "my_custom_yes_no_reference"
},
"type": "boolean",
"boolean": false
}
]
Why does .first work and why does .second not work ?
My OrdersController.rb
items = response.parsed_response["items"]
items.each do |item|
#order = current_user.orders.find_or_create_by(landing_id: item["landing_id"]) do |order|
item["answers"].each do |answer|
order.landing_id = item["landing_id"]
order.email = item["hidden"]["email"]
order.price = item["hidden"]["price"]
order.moduls = item["hidden"]["moduls"]
order.project = item["hidden"]["project"]
order.website = answer.first # This works
order.payment = answer.second # undefined method `second' for #<Hash:0x11f83e78>
end
end
end
You can do
answers.each { |answer| answer[:field] }
or, if you want ids for example
answers.map { |answer| answer.dig(:field, :id) }
Because ruby hash doesn't have any second or last methods. You can access value with the help of keys. e.g. answer[:type], answer[:text]
item["answers"].each do |answer| was an overkill. The solution was as simple as that:
order.website = item["answers"][1]["text] # Access the first field of answers array
order.payment = item["answers"][2]["text] # Access the second field of answers array

how to read individual data from the content of remote JSON file in Ruby on Rails?

I am trying to read individual data from the content of json API on Oil and Gas Authority website; however the code I have returns all the data. Any help would be highly appreciated.
require 'json'
require 'open-uri'
def index
url='http://data-ogauthority.opendata.arcgis.com/datasets/ab4f6b9519794522aa6ffa6c31617bf8_0.geojson'
#result = JSON.parse open(url).read
end
This my index view:
<% #result.each do |row| %>
<%= row %>
<% end %>
Given that the API (as you are currently using it) returns a JSON structure like this:
{
"type":"FeatureCollection",
"features":[
{
"type":"Feature",
"properties":{
"FIELDNAME":"GRYPHON",
"FIELDTYPE":"OIL",
"NAME_SHORT":"GRYPHON",
"STATUS":"PRODUCING",
"DISC_DATE":"1987/07",
"DISC_WELL":"9/18b-7",
"STAT_CODE":"800",
"PROD_DATE":"1993/10",
"DEPTH_M":"111.86",
"DET_STATUS":"DETERMINED",
"ORIG_OP":"KERR-MCGEE",
"ORIG_LIC":"P.496",
"ORIG_LIC_2":"P.478",
"ORIG_LIC_3":"P.257",
"ORIG_LIC_4":"P.103",
"ORIG_LIC_5":" ",
"CURR_OPER":"MAERSK OIL NORTH SEA UK LIMITED",
"FIELDDATA":"https://itportal.decc.gov.uk/fields/fields_index/ukcs+field+information+listed+by+field+name/183.htm",
"OBJECTID":16,
"OGA_COP":null
},
"geometry":{
"type":"Polygon",
"coordinates":[
[
[1.5701447246411744,59.35253688325039],
...
]
]
}
},
...
]
}
You could do something like:
<% #result[:features].each do |feature| %>
<%= feature[:properties][:FIELDNAME] %>
<%= feature[:properties][:FIELDTYPE] %>
...
<% end %>
Your JSON file looks to be something like 1.3MB. So, unless you can figure out how to filter your results on the API side (using query params, I would suppose), you may end up with various performance issues in retrieving the JSON.
And, you may want to do:
#result = JSON.parse(open(url).read).with_indifferent_access
So that you can use symbols to access hash elements as well as strings.
One thing to add to #jvillian answer is that if one of the keys is nil then calling this branch's subsequent keys will result in undefined method '[]'. Ruby 2.3+ has a new method called dig which will simply return nil. More on dig in my answer to this question.
Also to add to #jvillian answer, you can fetch the filtered information using this link; for example, taking into account the fields you need:
FIELDNAME
FIELDTYPE
STATUS
DISC_DATE
DISC_WELL
You could create query that will result in the following response:
{
"displayFieldName": "FIELDNAME",
"fieldAliases": {
"FIELDNAME": "Field Name",
"FIELDTYPE": "Field Type",
"STATUS": "Status",
"DISC_DATE": "Discovery Date",
"DISC_WELL": "Discovery Well"
},
"fields": [
{
"name": "FIELDNAME",
"type": "esriFieldTypeString",
"alias": "Field Name",
"length": 32
},
{
"name": "FIELDTYPE",
"type": "esriFieldTypeString",
"alias": "Field Type",
"length": 4
},
{
"name": "STATUS",
"type": "esriFieldTypeString",
"alias": "Status",
"length": 50
},
{
"name": "DISC_DATE",
"type": "esriFieldTypeString",
"alias": "Discovery Date",
"length": 20
},
{
"name": "DISC_WELL",
"type": "esriFieldTypeString",
"alias": "Discovery Well",
"length": 20
}
],
"features": [
{
"attributes": {
"FIELDNAME": "GRYPHON",
"FIELDTYPE": "OIL",
"STATUS": "PRODUCING",
"DISC_DATE": "1987/07",
"DISC_WELL": "9/18b-7"
}
},
{
"attributes": {
"FIELDNAME": "BRAEMAR",
"FIELDTYPE": "COND",
"STATUS": "PRODUCING",
"DISC_DATE": "1995/05",
"DISC_WELL": "16/03b-8Z"
}
},
...
]
}
This file will be now 76KB, and you can extract the data in almost the same way, just change properties for attributes, i.e.:
<% #result[:features].each do |feature| %>
<%= feature[:attributes][:FIELDNAME] %>
<%= feature[:attributes][:FIELDTYPE] %>
...
<% end %>

Rails 4 - Iterate through nested JSON params

I'm passing nested JSON into rails like so:
{
"product": {
"vendor": "Acme",
"categories":
{
"id": "3",
"method": "remove",
},
"categories":
{
"id": "4"
}
}
}
in order to update the category on a product. I am trying to iterate through the categories attribute in my products_controller so that I can add/remove the product to multiple categories at once:
def updateCategory
#product = Product.find(params[:id])
params[:product][:categories].each do |u|
#category = Category.find_by(id: params[:product][:categories][:id])
if params[:product][:categories][:method] == "remove"
#product.remove_from_category(#category)
else
#product.add_to_category(#category)
end
end
end
However, this only uses the second 'categories' ID in the update and doesn't iterate through both.
Example response JSON:
{
"product": {
"id": 20,
"title": "Heavy Duty Aluminum Chair",
"product_price": "47.47",
"vendor": "Acme",
"categories": [
{
"id": 4,
"title": "Category 4"
}
]
}
}
As you can see, it only added the category with ID = 4, and skipped over Category 3.
I'm fairly new to rails so I know I'm probably missing something obvious here. I've played around with the format of the JSON I'm passing in as well but it only made things worse.
You need to change your JSON structure. As you currently have it, the second "categories" reference will override the first one since you can only have 1 instance of a key. To get what you want, you should change it to:
{
"product": {
"vendor": "Acme",
"categories": [
{
"id": "3",
"method": "remove",
},
{
"id": "4"
}
]
}
}
You will also need to change your ruby code to look like:
def updateCategory
#product = Product.find(params[:id])
params[:product][:categories].each do |u|
#category = Category.find_by(id: u[:id])
if u[:method] == "remove"
#product.remove_from_category(#category)
else
#product.add_to_category(#category)
end
end
end

Displaying an object with Ruby on Rails

I have some JSON that looks like this. I have it stored and read into an object, #items.
[
{
{
"id": "A",
"description": "a_description"
},
{
"id": "B",
"description": "b_description"
}
},
{
{
"id": "A",
"description": "a_description"
},
{
"id": "B",
"description": "b_description"
}
}
]
My goal is to display a table with two columns, one labeled A and the other labeled B, in which each row gives the "a_description" and "b_description". I'm not sure how to go about doing this.
Ah, the ol' array of hashes and hashes of arrays problem.
To get around your "out of order" problem you first have to convert
{
"id": "A",
"description": "foo"
},
{
"id": "B",
"description": "bar"
}
into {"A" : "foo", "B" : "bar" }.
#new_items = #items.map do |item|
output = {}
item.each do |hash|
output.merge!(hash["id"] => hash["description"])
end
end
Then #new_items becomes (intentionally presented out of order since hash elements are not ordered)
[
{
"A": "a1_description",
"B": "b1_description"
},
{
"B": "b2_description",
"A": "a2_description"
}
]
From there, each line is simply a hash, so you can just dereference the value you need based on the column you're in.
#new_items.each do |item|
puts "#{item['A']} is paired with #{item['B']}"
end
Keys, of course could be retrieved dynamically if you don't want to hard code "A" and "B" using .keys
Something like this maybe
<tr><th>A</th><th>B</th></tr>
<% #items.each do |item| %>
<tr><td><%=item[0].description%></td><td><%=item[1].description%></td></tr>
<% end %>

Resources