Ruby Grape: How to send array of hashes as param - ruby-on-rails

I sends an array of hashes.
[{question_id: 1_id, answer:1_String},{question_id: 2_id, answer:2_String}]
and I used this code in my API file:
requires :profile_setting, type: Array[Hash], desc: "[{question_id: 1_id, answer: '1_String'},{question_id: 2_id, answer: '2_String'}]"
params: [{question_id: 1_id, answer:1_String},{question_id: 2_id, answer:2_String}]
response:
{
"error": "profile_setting is invalid"
}
how to send a Array of multiple hashes.

Your JSON misses quotes around keys and values.
Should be
[{
"question_id": "1 _id",
"answer": "1 _String"
},
{
"question_id": "2 _id",
"answer": "2 _String"
}]

Related

How to properly query Postgresql JSONB array of hashes on Ruby on Rails 6?

This is my column:
[
{ id: 1, value: 1, complete: true },
{ id: 2, value: 1, complete: false },
{ id: 3, value: 1, complete: true }
]
First, is there a "correct" way to work with a jsonb scheme? should I redesign to work with a single json instead of the array of hashes?
I have about 200 entries on the database, the column status has 200 of those itens.
How would I perform a query to get the count of true/false?
How can I query for ALL complete itens? I can query for the database rows in which the json has an item complete, but I can't query for all the itens, in all rows of the database that are complete.
Appreciate the help, thank you
Aha! I found it here:
https://levelup.gitconnected.com/how-to-query-a-json-array-of-objects-as-a-recordset-in-postgresql-a81acec9fbc5
Say your dataset is like this:
[{
"productid": "3",
"name": "Virtual Keyboard",
"price": "150.00"
}, {
"productid": "1",
"name": "Dell 123 Laptop Computer",
"price": "1300.00"
},
{
"productid": "8",
"name": "LG Ultrawide Monitor",
"price": "190.00"
}]
The proper way to count it, is like this:
select items.name, count(*) as num from
purchases,jsonb_to_recordset(purchases.items_purchased) as items(name text)
group by items.name
order by num Desc
Works like a charm and is extremely fast.
To do it in Rails, you need to use Model.find_by_sql(....) and indicate your select therem. I'm sure there are probably better ways to do it.

More efficient method than string replace with ruby gsub

I have a third party JSON feed which is huge - lots of data. Eg
{
"data": [{
"name": "ABC",
"price": "2.50"
},
...
]
}
I am required to strip the quotation marks from the price as the consumer of the JSON feed requires it in this way.
To do this I am performing a regex to find the prices and then iterating over the prices and doing a string replace using gsub. This is how I am doing it:
price_strings = json.scan(/(?:"price":")(.*?)(?:")/).uniq
price_strings.each do |price|
json.gsub!("\"#{price.reduce}\"", price.reduce)
end
json
The main bottle neck appears to be on the each block. Is there a better way of doing this?
If this JSON string is going to be serialised into a Hash at some point in your application or in another 3rd-party dependency of your code (i.e. to be consumed by your colleagues or modules), I suggest negotiating with them to convert the price value from String to Numeric on demand when the json is already a Hash, as this is more efficient, and allows them to...
...handle edge-case where say if "price": "" of which my code below will not work, as it would remove the "", and will be a JSON syntax error.
However, if you do not have control over this, or are doing once-off mutation for the whole json data, then can you try below?
json =
<<-eos
{
"data": [{
"name": "ABC",
"price": "2.50",
"somethingsomething": {
"data": [{
"name": "DEF",
"price": "3.25", "someprop1": "hello",
"someprop2": "world"
}]
},
"somethinggggg": {
"price": "123.45" },
"something2222": {
"price": 9.876, "heeeello": "world"
}
}]
}
eos
new_json = json.gsub /("price":.*?)"(.*?)"(.*?,|})/, '\1\2\3'
puts new_json
# =>
# {
# "data": [{
# "name": "ABC",
# "price": 2.50,
# "somethingsomething": {
# "data": [{
# "name": "DEF",
# "price": 3.25, "someprop1": "hello",
# "someprop2": "world"
# }]
# },
# "somethinggggg": {
# "price": 123.45 },
# "something2222": {
# "price": 9.876, "heeeello": "world"
# }
# }]
# }
DISCLAIMER: I am not a Regexp expert.
This is truly a fools errand.
JSON.parse('{ "price": 2.50 }')
> {price: 2.5}
As you can see from this javascript example the parser on the consuming side will truncate the float to whatever it wants.
Use a string if you want to provide a formatted number or leave formatting up to the client.
In fact using floats to represent money is widely known as a really bad idea since floats and doubles cannot accurately represent the base 10 multiples that we use for money. JSON only has a single number type that represents both floats and integers.
If the client is going to do any kind of calculations with the value you should use an integer in the lowest monetary denomation (cents for euros and dollars) or a string that's interpreted as a BigDecimal equivilent type by the consumer.

error: Json parsing in ruby

file= File.read('customers.json')
data_hash= JSON.parse( file)
# id=data_hash['customers'].map { |x| x['id'] }
data_hash['customers']['user_id'].each do |user|
latitude=user['customers']['latitude']
puts latitude
end
what error I am facing?
no implicit conversion of String into Integer (TypeError)
below is my json file
{
"customers" :[
{"latitude": "12.986375", "user_id": "12", "name": "Chris", "longitude": "77.043701"},
{"latitude": "11.92893", "user_id": "1", "name": "Alice", "longitude": "78.27699"},
{"latitude": "11.8856167", "user_id": "2", "name": "Ian", "longitude": "78.4240911"}
]
}
If you are trying to get latitude or something you should do it like:
file = File.read('customers.json')
data_hash = JSON.parse(file)
data_hash["customers"].each do |user|
latitude = user["latitude"]
puts latitude
end
OUTPUT:
12.986375
11.92893
11.8856167
The no implicit conversion of String into Integer (TypeError) error occurs when you try to treat an array as a hash. Since arrays expect integer keys for indexing Ruby will try to implicitly cast whatever gets passed to [] to an integer:
[]['a']
TypeError: no implicit conversion of String into Integer
In your case it's the data_hash['customers'] node that's an array.
You can actually just iterate through each item in data_hash[customers] mapping the value for the :latitude key back to an array via map.
puts data_hash["customers"].map { |h| h["latitude"] }

Create Nested Build for object rails

My JSON API is like below,
{ "schedule_id": "1",
"latitude" : 17.4327,
"longitude" : 78.4302,
"device_id": "123test",
"audit_compliances":[
{
"value": "Yes",
"score": 10,
"remarks": "some remarks",
"private_remarks": "some remarks",
"check_point_id": 1,
"audit_compliance_documents":[{
"score": 10,
"remarks": "some remarks",
}]
}]
i have a relations for that DB i want to save all this records at once so i want to initialize the object with details and build inner objects along with that. Started building like this but how can i build inner build for documents.
submission = Submission.new(audit_schedule_id: params[:schedule_id],
latitude: params[:latitude], longitude: params[:longitude],
device_id: params[:device_id])
params[:audit_compliances].each do |audit_compliance|
submission.audit_compliances.build(
value: audit_compliance[:value],
score: audit_compliance[:score],
remarks: audit_compliance[:remarks],
private_remarks: audit_compliance[:private_remarks],
check_point_id: audit_compliance[:check_point_id])
end
pass your json param in submission params directly
like this
params[:submission] = json_params;
Submission.create(params[:submission]);
It will create both if your mapping is correct........

Search a JSON Response using Ruby

I'm using a Ruby script to interface with an application API and the results being returned are in a JSON format. For example:
{
"incidents": [
{
"number": 1,
"status": "open",
"key": "abc123"
}
{
"number": 2,
"status": "open",
"key": "xyz098"
}
{
"number": 3,
"status": "closed",
"key": "lmn456"
}
]
}
I'm looking to search each block for a particular "key" value (yzx098 in this example) and return the associated "number" value.
Now, I'm very new to Ruby and I'm not sure if there's already a function to help accomplish this. However, a couple days of scouring the Googles and Ruby resource books hasn't yielded anything that works.
Any suggestions?
First of all, the JSON should be as below: (note the commas)
{
"incidents": [
{
"number": 1,
"status": "open",
"key": "abc123"
},
{
"number": 2,
"status": "open",
"key": "xyz098"
},
{
"number": 3,
"status": "closed",
"key": "lmn456"
}
]
}
Strore the above json in a variable
s = '{"incidents": [{"number": 1,"status": "open","key": "abc123"},{"number": 2,"status": "open","key": "xyz098"},{"number": 3,"status": "closed","key": "lmn456"}]}'
Parse the JSON
h = JSON.parse(s)
Find the required number using map
h["incidents"].map {|h1| h1['number'] if h1['key']=='xyz098'}.compact.first
Or you could also use find as below
h["incidents"].find {|h1| h1['key']=='xyz098'}['number']
Or you could also use select as below
h["incidents"].select {|h1| h1['key']=='xyz098'}.first['number']
Do as below
# to get numbers from `'key'`.
json_hash["incidents"].map { |h| h['key'][/\d+/].to_i }
json_hash["incidents"] - will give you the value of the key "incidents", which is nothing but an array of hash.
map to iterate thorough each hash and collect the value of 'key'. Then applying Hash#[] to each inner hash of the array, to get the value of "key". Then calling str[regexp], to get only the number strings like '098' from "xyz098", finally applying to_i to get the actual integer from it.
If the given hash actually a json string, then first parse it using JSON::parse to convert it to a hash.Then do iterate as I said above.
require 'json'
json_hash = JSON.parse(json_string)
# to get values from the key `"number"`.
json_hash["incidents"].map { |h| h['number'] } # => [1, 2, 3]
# to search and get all the numbers for a particular key match and take the first
json_hash["incidents"].select { |h| h['key'] == 'abc123' }.first['number'] # => 1
# or to search and get only the first number for a particular key match
json_hash["incidents"].find { |h| h['key'] == 'abc123' }['number'] # => 1

Resources