Rails JSON parse unexpected token escapced chars - ruby-on-rails

I have a string that has been escaped, I want to parse this into JSON but I keep getting errors using rails
{\"content\":{\"Soass__text_plain__abc_of_study\":\"Some of Study\",\"Dodeeedd\":
...........
........lots more of the string then comes some \u002d1 etc
Parse error on line 160:
... "id": \u002d1
JSON::ParserError: 399: unexpected token at '{"spacer":"http://s.c.xxx.yyyy.com/scds/common/u/img/spacer.gif","i18n_get_discovered_upload":"\u003cstrong\u003eGet discovered\u003c/strong\u003e for your work! Add your videos, images, documents...","bg_promo_1":
How can I JSON parse this?

You can build your json with hashes or with arrays, its more simple and clean
hash_of_values = {'foo' => 1, 'bar' => 2}
array_of_values = [hash_of_values]
And then :
JSON.parse(hash_of_values) => "{\"foo\":1,\"bar\":2}"
JSON.parse(array_of_values) => "[{\"foo\":1,\"bar\":2}]"

Related

Rails rspec CSV generator error for array of string in response

I've got specs for my CSV generator
RSpec.describe CsvAdminLogData::CsvAdminLogGenerator do
include_context 'with admin_user form'
subject(:csv_file) { described_class.new(start_date, end_date).call }
it 'creates CSV file with proper value' do
csv_file
log_file = CSV.open('app/custom/file.csv')
expect(log_file.to_a[1]).to match_array(
CSV.generate_line([
admin_log1.created_at,
admin_log1.action_type,
admin_log1.admin_email,
admin_log1.old_data,
admin_log1.new_data,
]),
)
end
With error:
expected collection contained: ["2019-06-17 16:39:22 +0200,New,orlandoratke#cruickshankmclaughlin.info,\"{\"\"email\"\"=>\"\"courtne...=>\"\"2019-09-16T16:39:22.880+02:00\"\", \"\"other_activities\"\"=>\"\"forbidden websites\"\"}\"\n"]
actual collection contained: ["2019-06-17 16:39:22 +0200", "New", "orlandoratke#cruickshankmclaughlin.info", "{\"email\"=>\"courtn... \"last_update\"=>\"2019-09-16T16:39:22.880+02:00\", \"other_activities\"=>\"forbidden websites\"}"]
the missing elements were: ["2019-06-17 16:39:22 +0200,New,orlandoratke#cruickshankmclaughlin.info,\"{\"\"email\"\"=>\"\"courtne...=>\"\"2019-09-16T16:39:22.880+02:00\"\", \"\"other_activities\"\"=>\"\"forbidden websites\"\"}\"\n"]
the extra elements were: ["2019-06-17 16:39:22 +0200", "New", "orlandoratke#cruickshankmclaughlin.info", "{\"email\"=>\"courtn... \"last_update\"=>\"2019-09-16T16:39:22.880+02:00\", \"other_activities\"=>\"forbidden websites\"}"]
So as far I see I've got an array of string instead of just an array. I was trying to handle it with something like this:
log_file = CSV.open('app/custom/file.csv').to_a
expect([log_file[1].join(',')])
But without results. I also tried to add ([... admin_log1.new_data,]).first.split(', ') at the end of expected results but I received an error NoMethodError: undefined method split' for Mon, 17 Jun 2019 16:14:56 CEST +02:00:Time
expect(log_file.to_a[1]).to match_array([
admin_log1.created_at,
admin_log1.action_type,
admin_log1.admin_email,
admin_log1.old_data,
admin_log1.new_data])
log_file will be something like [['a', 'b', 'b'], [...], ...].
By using CSV.generate_row you are converting the Array back to a String.
I don't suggest doing this but if you where just reading the file instead of parsing it you could use generate_line to create a String and compare it, as such:
csv = File.read('...')
.each_line
.drop(1) # remove header row
expect(csv[0]).to eq(CSV.generate_line([1,2,3])

String start with # return with backslash in rails console in some case

In console of rails 4.2.7, I have the following test:
[45] pry(main)> '#$'
=> "\#$"
[46] pry(main)> '##'
=> "\##"
[47] pry(main)> '#!'
=> "#!"
[48] pry(main)> '#ab'
=> "#ab"
It seems rails will only put a "\" before the string when there is an # or $ after #.
The problem leads me to this test is that I have a erb file that render a data attribute with an array of json:
data-xx="<%= [{xx: '#$', yy: 'yy'}.to_json, {zz: 'zzz'}.to_json] %>"
Then in chrome console, it will give the unexpected result as
$("#entry_show_modal_template").data('xx')
"["{\"xx\":\"\#$\",\"yy\":\"yy\"}", "{\"zz\":\"zzz\"}"]"
And when I change xx value from #! or some other string, the result will be ok as an array
$("#entry_show_modal_template").data('xx')
["{"xx":"#!","yy":"yy"}", "{"zz":"zzz"}"]
Does someone know if it is true and why it has such difference?
And it there any way to tackle this problem?
This is not true.
In '#{...}' hash will also be escaped. This is done to prevent recursive/implicit string interpolation.
Look:
$a = 'hello'
"#$a"
#⇒ "hello"
The problem is already solved by ruby for you. Just use the produced string as is and don’t be fooled by the way it is printed out in console.
"\#$".length
#⇒ 2
"\#$" == '#$'
#⇒ true
"\#$"[0]
#⇒ "#"
#mudasobwa's explaination is correct
According to your situation you should try in this way
===> In rails console
json_values = [{xx: '#$', yy: 'yy'}, {zz: 'zzz'}].to_json
===> In chrome console
result = JSON.parse(json_values)
you will get expected array, its just ruby technique to handle string interpolation thing

Parsing XML response with Rails 4 and Savon 2

I´m using Rails and Savon 2 to get data from a SOAP Webservice.
This is the code:
client = Savon.client(wsdl: "http://www.webservicex.net/periodictable.asmx?WSDL",
log_level: :debug,
pretty_print_xml: true)
message = {'ElementName' => 'Zinc'}
response = client.call(:get_element_symbol, message: message)
logger.debug "Body=" + response.body.to_s
symbol = response.to_hash[:get_element_symbol_response][:get_element_symbol_result][:NewDataDet][:Table][:Symbol]
The request is ok and I´m getting the data in the response:
Body={:get_element_symbol_response=>{:get_element_symbol_result=>"<NewDataSet>\n <Table>\n <Symbol>Zn</Symbol>\n </Table>\n</NewDataSet>", :#xmlns=>"http://www.webserviceX.NET"}}
But now, I don´t know how to parse this response correctly to get the "Symbol".
I´m getting this error:
`TypeError (no implicit conversion of Symbol into Integer):`
UPDATE:
If I do:
symbol = response.to_hash[:get_element_symbol_response][:get_element_symbol_result]
logger.debug "Symbol=" + symbol.inspect
I get this: Symbol="<NewDataSet>\n <Table>\n <Symbol>Zn</Symbol>\n </Table>\n</NewDataSet>"
I think the error is that I´m trying to get Symbol in hash mode, and it is not. But how can I get the symbol? I can´t believe I have to parse the string manually...
You can use nokogiri to parse XML text:
require 'nokogiri'
text = response.body[:get_element_symbol_response][:get_element_symbol_result]
Nokogiri::XML(text).css('Symbol').text # => Zn
# or
Nokogiri::XML(text).xpath('//NewDataSet/Table/Symbol').text # => Zn

Convert string to hash with ruby

I am saving one field as string in my model, so after that i tried via console
1.9.3-p547 :250 > s1 = s.send_details
=> "---\nnew_order: order\nprogress: order on d way\ndelivered:\n
message: delivered\n send_after: '1'\n"
1.9.3-p547 :255 > JSON.parse(s1)
JSON::ParserError: 757: unexpected token at '---
'
1.9.3-p547 :262 > s1.class
=> String
i am trying to convert this to json or hash, because i need to take the values from that, is there any way to do this?
Looks like your string is a YAML. You can easy decode it with YAML.load:
require 'yaml'
YAML.load("---\nnew_order: order\nprogress: order on d way\ndelivered:\n message: delivered\n send_after: '1'\n")
=> {"new_order"=>"order", "progress"=>"order on d way", "delivered"=>{"message"=>"delivered", "send_after"=>"1"}}

Why does the JSON returned from my Sinatra App give a syntax error?

I'm developing a Sinatra app, which returns JSON, e.g.
get '/clients' do
# do stuff
response = {
"success" => "true",
"msg" => "Clients successfully retrieved",
"data" => {"clients" => #current_user.clients}
}
return response.to_json
end
The returned JSON looks something like this:
{"success":"true","msg":"Clients successfully retrieved","data":{"clients":[{"client":{"created_at":"2013-03-31T22:50:18Z","email":"test#test.com","first_name":"Marge","gender":"F","hairdresser_id":2,"id":1,"surname":"Simpson","updated_at":"2013-03-31T22:50:18Z"}}]}}
When I copy and paste it into a JSON parser, it works fine.
http://json.parser.online.fr/
But when I fire up irb and try to use it, I get a bunch of errors:
1.9.3-p286 :001 > a = {"success":"true","msg":"Clients successfully retrieved","data":{"clients":[{"client":{"created_at":"2013-03-31T22:50:18Z","email":"test#test.com","first_name":"Marge","gender":"F","hairdresser_id":2,"id":1,"surname":"Simpson","updated_at":"2013-03-31T22:50:18Z"}}]}}
SyntaxError: (irb):1: syntax error, unexpected ':', expecting tASSOC
a = {"success":"true","msg":"Clients success...
^
(irb):1: syntax error, unexpected ',', expecting $end
a = {"success":"true","msg":"Clients successfully r...
^
from /home/[me]/.rvm/rubies/ruby-1.9.3-p286/bin/irb:13:in `<main>'
1.9.3-p286 :002 >
Anyone able to offer any insight? Am I doing something wrong?
Thanks alot
Problem
JSON doesn't constitute a valid Ruby hash. It's a String that you need to parse with JSON#parse.
Solution
Parse JSON as a String by enclosing it in single quotes or a Ruby quote literal. For example:
JSON.parse %q/{"success":"true","msg":"Clients successfully retrieved","data":{"clients":[{"client":{"created_at":"2013-03-31T22:50:18Z","email":"test#test.com","first_name":"Marge","gender":"F","hairdresser_id":2,"id":1,"surname":"Simpson","updated_at":"2013-03-31T22:50:18Z"}}]}}/
=> {"success"=>"true",
"msg"=>"Clients successfully retrieved",
"data"=>
{"clients"=>
[{"client"=>
{"created_at"=>"2013-03-31T22:50:18Z",
"email"=>"test#test.com",
"first_name"=>"Marge",
"gender"=>"F",
"hairdresser_id"=>2,
"id"=>1,
"surname"=>"Simpson",
"updated_at"=>"2013-03-31T22:50:18Z"}}]}}
Your hash has key value pair denoted as { key : value } but ruby uses '=>' symbol to map key to a value.
Try replacing ':' to '=>' and it works fine.
eg) a = {"success" => "true"}
If you want to parse this Json to ruby has then use this snippet:
require 'json'
value = "{\"val\":\"test\",\"val1\":\"test1\",\"val2\":\"test2\"}"
puts JSON.parse(value) # => {"val"=>"test","val1"=>"test1","val2"=>"test2"}

Resources