Parsing XML response with Rails 4 and Savon 2 - ruby-on-rails

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

Related

Seeding Data from JSON API to Ruby on Rails APP

I'm getting a no implicit conversion of String into Integer error that has me stumped, and unable to import user records and seed my database with them.
So far I have no problem accessing the data, but receive an error referencing the '[]' on the line with User.find... on it
The code I'm using is as follows:
require 'net/http'
require 'uri'
require 'json'
require 'faker'
#this script imports APR user data from the zendesk api and populates
the database with it.
uri = URI.parse("https://blahsupport.zendesk.com/api/v2/users.json")
request = Net::HTTP::Get.new(uri)
request.content_type = "application/json"
request.basic_auth("blah#blah.com", "blahpass")
req_options = {
use_ssl: uri.scheme == "https",
}
#response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
puts #response.body
puts #response.message
puts #response.code
info = #response.body
info.force_encoding("utf-8")
File.write('blahusers1.json', info)
puts "File Created Successfully!"
file = File.read('blahusers1.json')
users = JSON.load(file)
users.each do |a|
User.find_or_create_by_zendesk_id(:zendesk_id => a['id'], :url => a['url'], :name => a['name'], :email => a['email'])
end
Any ideas on how I've gotten this error? Thank you for any help!
**Edit
Below is an example of the data being returned.
{"users":[{"id":333653859,"url":"https://blahblah.zendesk.com/api/v2/users/333653859.json","name":"Randy Blah","email":"randy#blah.com","created_at":"2014-08-06T14:31:24Z","updated_at":"2018-04-04T14:22:06Z","time_zone":"Pacific Time (US & Canada)","phone":null,"shared_phone_number":null,"photo":{"url":"https://aprtechsupport.zendesk.com/api/v2/attachments/68955389.json","id":68955389,"file_name":"Work.jpg","content_url":"https://aprtechsupport.zendesk.com/system/photos/6895/5389/Work.jpg","mapped_content_url":"https://blahblah.zendesk.com/system/photos/6895/5389/Work.jpg","content_type":"image/jpeg","size":2528,"width":80,"height":80,"inline":false,"thumbnails":[{"url":"https://blahblah.zendesk.com/api/v2/attachments/68955399.json","id":68955399,"file_name":"Work_thumb.jpg","content_url":"https://blahblah.zendesk.com/system/photos/6895/5389/Work_thumb.jpg","mapped_content_url":"https://blahblah.zendesk.com/system/photos/6895/5389/Work_thumb.jpg","content_type":"image/jpeg","size":2522,"width":32,"height":32,"inline":false}]},"locale_id":1,"locale":"en-US","organization_id":null,"role":"admin","verified":true,"external_id":null,"tags":[],"alias":"","active":true,"shared":false,"shared_agent":false,"last_login_at":"2018-04-04T14:21:44Z","two_factor_auth_enabled":null,"signature":"Thanks for contacting the helpdesk!\n-Randy","details":"","notes":"","role_type":null,"custom_role_id":null,"moderator":true,"ticket_restriction":null,"only_private_comments":false,"restricted_agent":false,"suspended":false,"chat_only":false,"default_group_id":21692179,"user_fields":{}}
The example data you posted has a root object users that contains the array of user objects. So when you loop users using users.each, a is actually an Array and not a user Hash like you expected.
When you try to access an element of an Array using a 'String' index, it gives you the exception – no implicit conversion of String into Integer
So, try changing
users = JSON.load(file)
to
users = JSON.load(file)['users']
to get it working like how you'd expect.

how to access this kind of hash

I am using RestClient to make a post request and i made it so i an error response back so i can print those error messages in console
i tried the following per the restclient gem documentation
begin
response = RestClient.post base_uri, params.to_json, content_type: 'application/json', accept: 'application/json'
rescue RestClient::ExceptionWithResponse => err
error = err.response
p "this is the error response #{error}"
end
when i print err.response i get the following
"this is the error response {\"error\":{\"message\":\"An active access token must be used to query information about the current us
er.\",\"type\":\"OAuthException\",\"code\":2500,\"fbtrace_id\":\"HTzmJ0CcIfd\"}}"
how do i access the message in the above hash to display it in console?
tried
p "this is the error response #{error.message}"
and it gives me "Bad request" - have no idea where it gets that
If you're just looking to output it:
error = JSON.load(err.response)
puts error['error']['message']
You can always format it a bit better:
puts '[Code %d %s] %s' % [
error['error']['code'],
error['error']['type'],
error['error']['message']
]
Note that using puts inside of a Rails process is not going to work very well. You might want to use Rails.logger.debug instead.
The response you received is in JSON. You'll need to decode the JSON first and then interact with the data. Personally, I like MultiJson for this:
begin
response = RestClient.post base_uri, params.to_json, content_type: 'application/json', accept: 'application/json'
rescue RestClient::ExceptionWithResponse => err
error = MultiJson.load(err.response)
p "this is the error response #{error[:message]}"
end

Sunspot:solr - empty response

I'm trying to obtain response of solr for a given query. I've checked the solr query interface on localhost:8983 and its working fine, giving the required response to the queries. I want to select the productId field from each response and print it. Following is the code I'm using:
#!/usr/bin/ruby
# encoding: utf-8
require 'rubygems'
require 'solr'
solr = Solr::Connection.new('http://localhost:8983/solr')
response = solr.query('necklace')
puts "the response is:"
#puts response
puts "\n"
response.each do |hit|
puts hit['productId']
end
But it does not print anything, my response seems to be empty. How can I fix this
Try changing line 16 to:
puts hit['productId']

error passing json in rails (JSON::ParserError) "757: unexpected token in rails

I am trying to make a request from another url that calls back to my railsapp with a json responce and i get the following error in the process
757: unexpected token at 'https://voguepay.com/?v_transaction_id=demo-1355137288&type=json'
json (1.7.5) lib/json/common.rb:155:in `parse'
my controllers action is bellow
def get_response
#transaction_id = params[:transaction_id]
response = JSON.parse("https://voguepay.com/?v_transaction_id=#{#transaction_id}&type=json").body
end
any idea what i am doing wrong
I tried the url directly in my console window and i got the same error
the url is
https://voguepay.com/?v_transaction_id=demo-1345109950&type=json
I decided to use typhoeus gem and yajl-ruby gem. It all works fine for me and decided to share my solution below.
def notify
#transaction_id = params[:transaction_id]
hydra = Typhoeus::Hydra.new
request = Typhoeus::Request.new("https://voguepay.com/?v_transaction_id=#{#transaction_id}&type=json")
request.on_complete do |response|
transaction = Yajl::Parser.parse(response.body)
end
hydra.queue(request)
hydra.run
end

invalid URI - How to prevent, URI::InvalidURIError errors?

I got the following back from delayed_job:
[Worker(XXXXXX pid:3720)] Class#XXXXXXX failed with URI::InvalidURIError: bad URI(is not URI?): https://s3.amazonaws.com/cline-local-dev/2/attachments/542/original/mac-os-x[1].jpeg?AWSAccessKeyId=xxxxxxxx&Expires=1295403309&Signature=xxxxxxx%3D - 3 failed attempts
The way this URI comes from in my app is.
In my user_mailer I do:
#comment.attachments.each do |a|
attachments[a.attachment_file_name] = open(a.authenticated_url()) {|f| f.read }
end
Then in my attachments model:
def authenticated_url(style = nil, expires_in = 90.minutes)
AWS::S3::S3Object.url_for(attachment.path(style || attachment.default_style), attachment.bucket_name, :expires_in => expires_in, :use_ssl => attachment.s3_protocol == 'https')
end
That being said, is there some type of URI.encode or parsing I can do to prevent a valid URI (as I checked the URL works in my browser) for erroring and killing delayed_job in rails 3?
Thank you!
Ruby has (at least) two modules for dealing with URIs.
URI is part of the standard library.
Addressable::URI, is a separate gem, and more comprehensive, and claims to conform to the spec.
Parse a URL with either one, modify any parameters using the gem's methods, then convert it using to_s before passing it on, and you should be good to go.
I tried ' open( URI.parse(URI.encode( a.authenticated_url() )) ' but that errord with OpenURI::HTTPError: 403 Forbidden
If you navigated to that page via a browser and it succeeded, then later failed going to it directly via code, it's likely there is a cookie or session state that is missing. You might need to use something like Mechanize, which will maintain that state while allowing you to navigate through a site.
EDIT:
require 'addressable/uri'
url = 'http://www.example.com'
uri = Addressable::URI.parse(url)
uri.query_values = {
:foo => :bar,
:q => '"one two"'
}
uri.to_s # => "http://www.example.com?foo=bar&q=%22one%20two%22"

Resources