to_json on single value can't be parse back - ruby

i'm trying to implement wysihml5 in a sinatra app using Activerecord.
The rich text editor works great and when i submit the form i got right html post to controller:
pry:> request.params
=> {"title" => "title text",
"content" => "<b>bold text</b><br><i>italic text</i>",
"_wysihtml5_mode" => 1
}
Then, i remove hash entry "_wysihtml5_mode" from request.params to create the db entry, then i convert content to json:
pry:> request.params.delete("_wysihtml5_mode")
=> 1
pry:> request.params["content"].to_json
=> "\"\\u003Cb\\u003Ebold text\\u003C/b\\u003E...
pry:> class.create(request.params)
The problem is i can't get my value back as begining:
pry:> class.last.content
=> "\"\\u003Cb\\u003Ebold text\\u003C/b\\u003E...
pry:> JSON.parse(class.last.content)
JSON::ParseError: 743: unexpected token at '"\\u003Cb\\u003Ebold text\\u003C/b\\u003E...
How could i get back this unicode charcters to their utf-8 style (i might be wrong, i m not comfortable with characters table). It seems that during convertion to json, a " is added at the begining:
"<b>bold => "\"\\u003Cb\\u003Ebold
This might be the problem? Any ideas?

The problem comes from calling to_json on a single value. This doesn't produce a full JSON representation. Here is some examples:
"hello".to_json
=> "\"hello\""
JSON.parse("hello".to_json)
=> JSON::ParseError: 743: unexpected token at...
nil.to_json
=> "null"
JSON.parse(nil.to_json)
=> JSON::ParseError: 743: unexpected token at...
Fortunately, the JSON parser come with a "quirks mode" who allow to parse single values:
"hello".to_json
=> "\"hello\""
JSON.parse("hello".to_json, {:quirks_mode => true})
=> "hello"
nil.to_json
=> "null"
JSON.parse(nil.to_json, {:quirks_mode => true})
=> nil
I'm not sure of what :quirks_mode is really doing, maybe someone could explain it a bit?

Related

Ruby - API RestClient - JSON

Just getting started with API testing and struggling, used to just doing front end selenium web-driver tests, however, I need to get my head around API testing.
I kind of understand the basics such as Get will get the data from the url and post will post data to the url, I think that is correct, however, I could be wrong.
The issue I am having is below:
response = RestClient.post 'http://jsonplaceholder.typicode.com/posts',
{:title => 'mr', :first_name => 'bob', :second_name => 'smith'}
data1 = JSON.parse(response)
p data1
So I am assigning the restclient.post to the response variable and posting the hash key, value pairs to the url? Then I am using JSON to parse the response and then printing the response to the console. What I need to do is extract each value from the hash and print each value to the console so it shows the data as mr bob smith. Instead of {:title => 'mr', :first_name => 'bob', :second_name => 'smith'}
print "#{ data1[ :title ]} #{data1[:first_name]} #{data1[:second_name]}"

Ruby find key by name inside converted JSON array of hashes

I have a Ruby hash converted from JSON data, it looks like this:
{ :query => {
:pages => {
:"743958" => {
:pageid => 743958,
:ns => 0,
:title => "Asterix the Gaul",
:revisions => [ {
:contentformat => "text/x-wiki",
:contentmodel => "wikitext",
:* => "{{Cleanup|date=April 2010}}\n{{Infobox graphic novel\n<!--Wikipedia:WikiProject Comics-->...
All the good stuff is inside the revisions array and then the Infobox hash.
The problem I have is getting to the Infobox hash. I can't seem to get to it. The pages and pageid hashes might not exist for other entries and of course the ID would be different.
I've tried all sorts of methods I could think of like .map, .select, .find, .include?, etc to no avail because they are not recursive and will not go into each key and array.
And all the answers I've seen in StackOverflow are to get the value by name inside a one-dimensional array which doesn't help.
How can I get the Infobox data from this?
Is this what you're looking for?
pp data
=> {:query=> {:pages=>
{:"743958"=>
{:pageid=>743958,
:ns=>0,
:title=>"Asterix the Gaul",
:revisions=>
[{:contentformat=>"text/x-wiki",
:contentmodel=>"wikitext",
:*=>"{{Cleanup..."}]}}}}
# just return data from the first revisionb
data[:query][:pages].map{|page_id,page_hash| page_hash[:revisions].first[:"*"]}
=> ["{{Cleanup..."]
# get data from all revisions
data[:query][:pages].map{|page_id,page_hash| page_hash[:revisions].map{|revision| revision[:"*"] }}.flatten
=> ["{{Cleanup..."]

Ruby's Mechanize balks when selecting a radio button (maybe because its name is capitalized) but Perl's WWW::Mechanize works fine

I'm trying to submit a form with Ruby's Mechanize gem. This form has a set of radio buttons named "KeywordType". The individual buttons are named something like rdoAny, rdoAll and rdoPhrase. With Perl's WWW:Mechanize it works just fine:
my $result = $agent->submit_form(
form_number => 1,
fields => {
txtKeywords => 'foo bar baz',
lstLocationCode => '2100',
lstONETMajorGroup => '0',
KeywordType => 'rdoAny'
},
button => 'btnSearch'
);
but Ruby balks when I do this:
result = page.form_with(:id => 'frmSearch') do |field|
field.txtKeywords = 'foo bar baz'
field.lstLocationCode = '2100'
field.lstONETMajorGroup = '0'
field.KeywordType = 'rdoAny'
end.submit
This throws the error
"undefined method `KeywordType=' for #<Mechanize::Form:0x00000001c896e0> (NoMethodError)".
I've tried leaving out the KeywordType field, but then I just get sent back to the same page with no obvious error message. I've also tried doing things like field.radiobuttons.second.check and field.radiobuttons_with(:name => "KeywordType") to no avail.
And on a side note, is whatever's going on because Ruby sees a capitalized radiobutton name and thinks it's a constant?
Thanks.
Does this work?
field['KeywordType'] = 'rdoAny'
Edit: Oh, and I think you missed a part here:
result = page.form_with(:id => 'frmSearch') do |field|
should be (I think):
result = page.form_with(:id => 'frmSearch').fields.each do |field|
Gaah. The outdated version gremlin strikes again. "gem update mechanize" is now at least showing me the values for the two dropdowns.

In Ruby, how to upload multiple files in single request using RESTClient

I have to upload multiple files as form request. I am using the Rest Client to post my request. I am able to upload single file but I am not sure how to add multiple files in a single request.
I searched/googled for such option and I am not finding any solution that solves my problem.
Below is my code.
It has variable argument (*yamlfile) which takes one or more files. I have to upload all the files together.
The issue now is , I am getting syntax error when I add the loop to extract the file within the payload.
my assumption is now to form this outside the payload and include it inside the payload block but I am not sure how to do it.
Can someone help me with that.
( I have tried net/http/post/multipart library too and I don't find much documents around it)
def uploadRest(endpoint,archive_file_path,,yaml_file_path,*yamlfile)
$arg_len=yamlfile.length
request = RestClient::Request.new(
:method => :post,
:url => endpoint,
:payload => {
:multipart => true,
:job_upload_archive => File.new(archive_file_path,'rb'),
:job_upload_path => "/tmp",
# Trying to add multiple file, but I get syntax error
yamlfile.each_with_index { |yaml, index|
:job_upload_yaml_file+index => File.new("#{yaml_file_path}/#{pmml}")
}
})
response=request.execute
puts response.code
end
uploadRest(endpoint,archive_file_path,yaml_file_path,*yamlfile)
#files=Array.new
yamlfile.each{ |yaml_file|
#files.push(File.new("#{yaml_file_path}/#{yaml_file}"))
}
request = RestClient::Request.new(
:method => :post,
:url => endpoint,
:payload => { :multipart => true, :job_upload_archive => File.new(archive_file_path,'rb'),
:job_upload_path => "/tmp", :job_upload_yaml_file => #files })
response=request.execute
end
I had a similar problem and was able to get this to work by passing an array of arrays as a requests.
file1 = File.new("#{yaml_file_path}/#{yaml_file1}", 'rb')
file2 = File.new("#{yaml_file_path}/#{yaml_file}", 'rb')
request_body = [["files", file1], ["files", file2]]
RestClient.post url, request_body, request_headers
There were two issues with your question code:
1) Attempt to add a symbol to an integer
2) Attempt to insert contents of yamlfile direct into the hash (because that is what yamlfile.each_with_index returns, as opposed to how it calls your block. The return value from the block is not used)
Both of these code issues read as if you have gained experience in HAML or another templating language, and are using structures/ideas that would work in that?
There are lots of possble solutions in Ruby, but a simple approach to build up the hash in parts, as opposed to generate it in one go with clever hash-returning routines embedded. Try something like this:
payload_hash = {
:multipart => true,
:job_upload_archive => File.new(archive_file_path,'rb'),
:job_upload_path => "/tmp",
}
# This does not use the return value from each_with_index, instead it relies
# on the block to make changes to the hash by adding new key/value pairs
yamlfile.each_with_index { |yaml, index|
# This concatenates two strings, and then converts the combined
# string into the symbol that you want
file_key = ("job_upload_yaml_file"+index.to_s).to_sym
payload_hash[file_key] = File.new("#{yaml_file_path}/#{yaml}")
}
request = RestClient::Request.new(
:method => :post,
:url => endpoint,
:payload => payload_hash
)
For added code cleanliness, you could make the first two parts a separate method, and call it where it currently has payload_hash.
This should get you over current syntax hurdles. However, I have made no attempt to check whether this will allow you to upload multiple files via RESTClient.
Section1:
#params = {
"FacialImage" => UploadIO.new(File.new('C:\temp\ATDD\Test\test\sachin.jpg'), "image/jpeg"),
"Login" => UploadIO.new(File.new('C:\temp\ATDD\Test\test\login.txt'), "application/json")
}

Ruby RestClient converts XML to Hash

I need to send a POST request as an XML string but I get odd results. The code:
require 'rest_client'
response = RestClient.post "http://127.0.0.1:2000", "<tag1>text</tag1>", :content_type => "text/xml"
I expect to receive "<tag1>text</tag1>" as the parameter on the request server. Instead, I get "tag1"=>"text". It converts the XML to a hash. Why is that? Any way around this?
Try this:
response = RestClient.post "http://127.0.0.1:2000",
"<tag1>text</tag1>",
{:accept => :xml, :content_type => :xml}
I think you just needed to specify the ":accept" to let it know you wanted to receive it in the XML format. Assuming it's your own server, you can debug on the server and see the request format used is probably html.
Hope that helps.
Instead of using RestClient, use Ruby's built-in Open::URI for GET requests or something like Net::HTTP or the incredibly powerful Typhoeus:
uri = URI('http://www.example.com/search.cgi')
res = Net::HTTP.post_form(uri, 'q' => 'ruby', 'max' => '50')
In Typhoeus, you'd use:
res = Typhoeus::Request.post(
'http://localhost:3000/posts',
:params => {
:title => 'test post',
:content => 'this is my test'
}
)
Your resulting page, if it's in XML will be easy to parse using Nokogiri:
doc = Nokogiri::XML(res.body)
At that point you'll have a fully parsed DOM, ready to be searched, using Nokogiri's search methods, such as search and at, or any of their related methods.

Resources