Rails: parse weirdly-formatted JSON - ruby-on-rails

My JSON response from an external service looks like this:
Parameters: {"{\"attributes\":{\"type\":\"Lead\",\"url\":\"/services/lead/2231\"},\"Id\":\"2231\",\"FirstName\":\"Jean\"}"=>nil, "external_id"=>"2231"}
How can I parse the Id and FirstName keys in Rails 5? I've tried everything. I know Rails 5 has the .to_unsafe_h method, that's not my problem. It's more the weird nested formatting that has a value of nil after "Jean" above.

If you pay attention closely, you will see:
"{\"attributes\":{\"type\":\"Lead\",\"url\":\"/services/lead/2231\"},\"Id\":\"2231\",\"FirstName\":\"Jean\"}" is actually a string, a key, and the value value associated to it is nil.
If you want to parse that, just can use parameters.keys[0].to_json; although I will double check first why you are getting the parameters in that incorrect state in the first place.

Related

response checksum or hash not matching in payumoney?

When notification is passed to the app after payumoney processing it sends response hash and we need to compute the hash and match it with the passed in response hash.
I use the following code to compute the expected response hash.
Digest::SHA512.hexdigest([
PAYU_SALT,
notification.transaction_status,
notification.user_defined,
notification.customer_email,
notification.customer_first_name,
notification.product_info,
notification.gross,
notification.invoice,
PAYU_KEY].join("|"))
The hash of the following string is computed
"salt|success|||||||||||||Payment|100.0|1|key"
When I print the following hash it gives
Digest::SHA512.hexdigest([
PAYU_SALT,
notification.transaction_status,
notification.user_defined,
notification.customer_email,
notification.customer_first_name,
notification.product_info,
notification.gross,
notification.invoice,
PAYU_KEY].join("|"))
#⇒ e7b3c5ba00b98aad9186a5e6eea65028a[...]
whereas notification.checksum gives
#⇒ 546f5d23e0cadad2d4158911ef72f095d[...]
So the two hashes don’t match.
I am using the following gem: https://github.com/payu-india/payuindia
I appreciate any help as to why the response hash is not matching. Is there any error in my logic to compute the response hash? Thanks!
Where did you come up with that order for the fields in the array?
Looking at PayU's Developer FAQ it seems like the order is the following:
key|txnid|amount|productinfo|firstname|email|||||||||||salt
Please make sure that the hash is calculated in the following format - hashSequence= key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt
Please make sure that in the above sequence please use the UDFs which have also been posted to our server. In case you haven't posted any UDFs, the hash sequence should look like this - hashSequence= key|txnid|amount|productinfo|firstname|email|||||||||||salt.
Keep in mind that when computing the hash even a single character out of place will result in a completely different checksum.
little late but Actual Sequence is:
SALT|status||||||udf5|udf4|udf3|udf2|udf1|email|firstname|productinfo|amount|txnid|key
Thanks to Ravi Kant Singh
but additionalCharges| are removed
Tested with live environment
Check your hash in above order and if its match you can process request
ok this was a silly mistake i made. The reason the hash didn't match was beacuse i had a typo with the PAYU test key. At the end i typed small 'u' when it was 'U'. The library is fine and the logic is right. The error was in my side with using wrong key.
Actual Sequence for hash is :
additionalCharges|SALT|status||||||udf5|udf4|udf3|udf2|udf1|email|firstname|productinfo|amount|txnid|key
Actual hash generation for additional charges:
additionalCharges|SALT|status||||||udf5|udf4|udf3|udf2|udf1|email|firstname|productinfo|amount|txnid|key
Without additional charges:
SALT|status||||||udf5|udf4|udf3|udf2|udf1|email|firstname|productinfo|amount|txnid|key

JSON serializing and deserializing with special characters with RAILS

I really feel a bit stupid as to what to do to make this simple line work, I looked around, and no answer seemed to really answer this, can anyone can tell me how to serialize and deserialize something as simple as that:
JSON.parse("É".to_json)
JSON::ParserError: 757: unexpected token at '"\u00e9"'
EDIT:
The real problem was more akin to saving a hash in the database with a é in the string, like this:
{"Hu00c9MO":"JOUR"}
It seems the string is not good, and I can't bring back the é after decoding from JSON
I think the problem is not the "É". I just tried this:
JSON.parse("A".to_json)
JSON::ParserError: 757: unexpected token at '"A"'
And as you can see it throws the same type of error.
The problem here is that a single string as "É" is not a valid JSON, and even though you can use to_json to serialize it, when you try to parse it, it will hang. Try this for example:
JSON.parse({'key' => 'É'}.to_json)
As stated in the docs:
JSON.generate only allows objects or arrays to be converted to JSON
syntax. to_json, however, accepts many Ruby classes even though it
acts only as a method for serialization
(.to_json is just an alternative to JSON.generate)
Accord http://www.json.org/ JSON should be an object {id: value} or an array [value1, value2].
You are passing to parse only a value. Try something like: JSON.parse(["É"].to_json) or JSON.parse({value: "É"}.to_json)
EDIT As Question was Edited:
Accord http://www.json.org When JSON is on object {id: value}, id can be Any UNICODE charecter except " or \ or control charecter This is the reason why you can't get back "É" in the id side.
Maybe the solution is replace "\" with another valid character before save into DB and do the reverse replace when you read it from DB or just escape "\" with "\".

Passing array of parameters through get in rails

How do I pass array of parameters through Get method in rails? Currently my URL loocs like this:
http://localhost:3000/jobs/1017/editing_job_suites/1017/editing_member_jobs/new?ids[]=1025&ids[]=1027
How can I pass the array with Get method but avoid ?ids[]=1025&ids[]=1027 part.
Request is being sent with javascript window.open method. Is there any workaround to send not ajax Post request.
You should stick to using a GET request if you are not changing the state of anything, and all you want to to access a read only value.
To send an array of ids to rails in a GET request simply name your variable with square brackets at the end.
//angular snippet
$http.(method:'GET',
...
params: {'channel_id':2, 'product_ids[]': productIds}
//where productIds is an array of integers
...
)
Do not concatenate your ids as a comma separated list, just pass them individually redundantly. So in the url it would look something like this:
?channel_id=2&product_ids[]=6900&product_ids[]=6901
url encoded it will actually be more like this:
?channel_id=2&product_ids%5B%5D=6900&product_ids%5B%5D=6901
Rails will separate this back out for you.
Parameters: {"channel_id"=>"2", "product_ids"=>["6900", "6901"]}
No, GET can only put variables on the url itself. If you want the URL to be shorter, you have to POST. That's a limitation feature of HTTP, not Rails.
I recently wanted to do this and found a workaround that is a little less complex, and so has some complexity limitations but may also be easier to implement. Can't speak to security, etc.
If you pass your array values as a string with a delimiter, e.g.
http://example.com/controller?job_ids=2342,2354,25245
Then you can take the result and parse it back to what you want:
job_ids = params[:job_ids].split(',')
Then do whatever:
job_ids.each do |job_id|
job = Job.find(job_id.to_i)
end
etc
#Homan answer is valid for using an external client (e.g curl or angular). Inside Rails test cases though, you should not use []. Here's an example:
get get_test_cases_url(**path_params), params: {case_ids: ["NON-9450", "NON-12345", "NON-9361"]}
This is using new format where get_test_cases is name of route and you pass to the method all params needed to construct the URL path. Query params are a separate hash.
FYI if I use [] like case_ids[], then instead of ["NON-9450", "NON-12345", "NON-9361"] I'm getting it parsed to [["NON-9450"], ["NON-12345"], ["NON-9361"]]

How to format a date to JSON in Rails?

I need to produce a date in Rails which looks like this:
/Date(1294268400000)/
I have tried various combinations of DateTime, to_i, to_json but never managed to get the /Date()/ thing.
Do I have to simply get my date in ms and then wrap the /Date(and )/ manually, or is there a built in method?
What about (ruby 1.9.x)?:
Time.now.strftime("/Date(%s%L)/")
=> "/Date(1335280866211)/"
You should try
new Date(posixMillisecondsHere)
first. MDN says that calling the Date function outside of the constructor context (i.e., without the new) will always return a string containing a formatted date rather than a Date object.
Strictly speaking, when you do that, you are writing JavaScript and not JSON. JSON cannot contain Date objects.
RFC 4627 says
2.1. Values
A JSON value MUST be an object, array, number, or string, or one of
the following three literal names:
false null true
If you want to put a Date into what is strictly considered JSON and then get it back out, you must choose some way of using the JSON primitives (to wit, objects, arrays, numbers, strings, etc.) to encode a Date.
If you want to get a Date back out of JSON, whatever parses your JSON must understand the convention that you used to encode the Date.
Hope these are credible and/or official enough to help.
What about something like this:
in your config/en.yml file:
en:
time:
formats:
json: "/Date(%s%L)/"
and than in the view:
<%= l(Time.now, :format => :json) %>
Please note that you would need access to the helpers in the method that renders json. So it won't work if you are using ActiveRecord#to_json method for generating jsons.
Check out this question:
c# serialized JSON date to ruby
... simple answer seems to be to create a parse_date method.
It's the UNIX Epoch (seconds since 1970-01-01) right? What about using DateTime#strftime method?
# Taken from the Ruby documentation
seconds_since_1970 = your_date.strftime("%s")
UPDATE: OK, it's milliseconds, according to the documentation you can use your_date.strftime("%Q") to get the ms (but I've not tried yet).

rails, cannot get params from url

I'm trying to use Google Federated Login REST API. I can succesfully reach out to the google server and validate a user but I cannot pull parameters from the return url
for example:
http://mysite.com/login/return?openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.mode=id_res&openid.op_endpoint=https%3A%2F%2Fwww.google.com%2Faccounts%2Fo8%2Fud...
All the variables in that return string are not accessible in the params array. I have no idea how to get them out. requst.url, request.query_parameter, and all similar calls do not return the query string.
I think i found the issue. I was using the open-uri library to make the call to google's endpoint url so it may have been stepping outside of the normal rails response/request cycle. I've since used Net::HTTP requests and parse the information from the response.
So I have a very similar issue, where I'm actually building a Rails-based openid provider but being consumed by another Rails app. I basically adapted the code from
The whole URL was:
http://localhost:3000/openid?openid.assoc_handle=%7BHMAC-SHA1%7D%7B5193d33f%7D%7BdBrUwQ%3D%3D%7D&openid.claimed_id=http%3A%2F%2Flocalhost%3A3000%2Fopenid%2Fwarren&openid.identity=http%3A%2F%2Flocalhost%3A3000%2Fopenid%2Fwarren&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.ns.sreg=http%3A%2F%2Fopenid.net%2Fextensions%2Fsreg%2F1.1&openid.realm=http%3A%2F%2Flocalhost&openid.return_to=http%3A%2F%2Flocalhost%2Fsession%3F_method%3Dpost%26return_to%3D&openid.sreg.required=nickname%2Cemail
I had a similar problem where the only parameters being reported were:
{"action"=>"index", "controller"=>"openid"}
So, suspecting that some parameter (maybe a period?) was causing it to hiccup, I went through and deleted them one by one until I found that deleting the following parameter enables the entire thing to go through correctly:
openid.mode=checkid_setup
That left all the remaining parameters correctly being parsed:
{"openid.assoc_handle"=>"{HMAC-SHA1}{5193d33f}{dBrUwQ==}",
"openid.claimed_id"=>"http://localhost:3000/openid/warren",
"openid.identity"=>"http://localhost:3000/openid/warren",
"openid.ns"=>"http://specs.openid.net/auth/2.0",
"openid.ns.sreg"=>"http://openid.net/extensions/sreg/1.1",
"openid.realm"=>"http://localhost",
"openid.return_to"=>"http://localhost/session?_method=post&return_to=",
"openid.sreg.required"=>"nickname,email",
"action"=>"index",
"controller"=>"openid"}
I'm now trying to find why openid.mode causes this issue. It fails even if I change it to openid.mode=5, so it's the key, not the value, causing the problem.
Suspecting the ".mode" part of the string for the trouble (maybe ".mode" is a filetype or something being parsed by the routing?) I am looking towards this post on allowing periods, but it only applies to the value, not the key: rails routing and params with a '.' in them
Will report back if I find more.
Update: I tried, in another Rails app, adding ?openid.mode=0 to the end of a URL -- ".mode" does not result in a parameter being read, but ".modes=" does and so does ".mod=". This confirms that ".mode" is causing a params parsing error.
Update 2: yikes... actually "?a.mode=0" does work. So far, only the complete string "openid.mode" does not work, and this is across various Rails apps. "?openid.mode" with nothing else results in: Parameters: {"openid.mode"=>nil}, but "?openid.mode=" with nothing after the "=" fails to pass any parameters besides action & controller. Very odd.
Update 3: OK, figured it out, I believe -- the params were getting sanitized i.e. deleted by the rack-openid gem, in that gem's path: /lib/openid.rb:168, "sanitize_query_string". This seems to be incompatible with the example I was working with: https://github.com/openid/ruby-openid/tree/master/examples/rails_openid. Going to override that method.
Final update: I replaced this line:
oidreq = server.decode_request(params)
with this line, since we could no longer use the now-empty params hash:
oidreq = server.decode_request(Rack::Utils.parse_query(request.env['ORIGINAL_FULLPATH']))

Resources