Rails App on Google Cloud: URI must be ascii only - ruby-on-rails

I have a working request on localhost, which basically calls and endpoint using an address
def stuart_validate_address(address)
require 'uri'
require 'net/http'
### not working with accents like Calàbria
# url = URI("https://api.stuart.com/v2/addresses/validate?type=picking&address=#{address}")
# url = URI.parse("https://api.stuart.com/v2/addresses/validate?type=picking&address=#{address}")
url = URI.parse(URI.escape("https://api.stuart.com/v2/addresses/validate?type=picking&address=#{address}"))
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(url)
request["authorization"] = "Bearer #{AUTH_TOKEN}"
request.body = "{}"
response = http.request(request)
JSON.parse(response.read_body)
end
If I use the endpoint with Postman it works, if I do the call with localhost it works. But once we are on production (gcloud) it complains about
URI::InvalidURIError
URI must be ascii only "https://api.stuart.com/v2/addresses/validate?type=picking&address=Córsega 494, 08025, Barcelona"
I know I have to parse it and escape it, but I can't figure out why I still have the same error. Also I am curious why it's working on localhost and postman, and not in Rails production environment.

The issue is that you have an acute ó in your url.
If you are using Rails, you can use string#parameterize
Or if plain Ruby, you use i18n gem:
require "i18n"
I18n.transliterate("Olá Mundo!")
=> "Ola Mundo!"

Related

Rails http GET request with no ssl verification and basic auth

I am trying to make a http get request as specified in the title.
What I've written:
uri = URI.parse("https://myaddress.com")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
#data = http.get(uri.request_uri)
The request is sent where I want it to be sent and I receive an Unauthorized response (as expected, because I did not specify the basic auth).
I've tried
http.basic_auth 'user', 'pass'
But there's no such method for the type of my http variable.
How can I add the auth details?
Update: I tried to use something like here RUBY - SSL, Basic Auth, and POST, but after replacing Post with Get, I cannot use the 'use_ssl', nor 'verify_mode' attributes (I get no such attribute error).
Update 2: I figured out that I can set the 'use_ssl' attribute on a Net::HTTP object and the 'basic_auth' on a Net::HTTP::Get object.
Now the question is how can I make them work together?
Well, I ended up finding an answer. Maybe this will help others:
url = URI.parse('https://myaddress.com')
req = Net::HTTP::Get.new(url.path)
req.basic_auth 'user', 'pass'
sock = Net::HTTP.new(url.host, url.port)
sock.use_ssl = true
sock.verify_mode = OpenSSL::SSL::VERIFY_NONE
resp = sock.start {|http| http.request(req) }

curl to Ruby request for connecting to wheniwork

Back story
I've spent a few days on the Ruby gem for wheniwork, and it's been a nightmare. To make a long story short, the gem had a dependency of an older version of activesupport and I basically forked their repo and made a compatible version for my ruby project. I was able to create a new gem and attempted to use it, but I was getting the following json message:
{"error"=>"User login required for this resource.", "code"=>1000}
The username, password, and api key were set. What I basically need to do is access our account on wheniwork, and retrieve data.
This is an example using the curl command
curl https://api.wheniwork.com/2/login \
--data '{"username":"user#example.com","password":"*******"}' \
-H "W-Key: iworksoharditsnotfunny"
Essentially, I would get some kind of return object from wheniwork that would contain the token. I'd use this token for future requests to the wheniwork site.
To (Ruby)
A new attempt to translate this to Ruby
require 'net/http'
data = {'credentials' => {'username' => 'XXXXX#XXXXX.com','password' => 'XXXXX', 'W-Key' => '111111111XXXXX'}}
uri = URI.parse("https://api.wheniwork.com/2/login/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' =>'application/json'})
request.add_field('Content-Type', 'application/json')
request.body = data.to_json
response = http.request(request)
Result:
#<Net::HTTPUnauthorized 401 Unauthorized readbody=true>
If you have any idea or clue (or basically anything that would help me here), I would appreciate it beyond words. Thanks!
Got it!! The major issue(s) were that the api key and (username+password) combo are two separate pieces.
I was so close the entire time, but here it is:
data = {'username' => 'XXXX#XXXXXXX.com','password' => 'XXXXX'}
uri = URI.parse("https://api.wheniwork.com/2/login/")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(uri.path)
request.add_field('W-Key', 'XXXXXXXXXXXXX')
request.body = data.to_json
response = http.request(request)
puts JSON.parse(response.body)

Ruby github API

I am new to ruby programming. I was trying to write below ruby code to create a comment in Github gist.
uri = URI.parse("https://api.github.com/gists/xxxxxxxxxxx/comments")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.scheme == 'https')
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(uri.request_uri)
request.body = {
"body" => "Chef run failed "
}.to_json
response = http.request(request)
response2 = JSON.parse(response.body)
puts response2
But I executed below script then I always get {"message"=>"Not Found", "documentation_url"=>"https://developer.github.com/v3"}
Don't know what I am doing wrong. Appreciate help.
Make sure that you're authenticated first. From the Github API docs on Authentication:
There are three ways to authenticate through GitHub API v3. Requests
that require authentication will return 404 Not Found, instead of 403
Forbidden, in some places. This is to prevent the accidental leakage
of private repositories to unauthorized users.
You can do this by creating an OAuth2 token and setting it as an HTTP header:
request['Authorization'] = 'token YOUR_OAUTH_TOKEN'
You can also pass the OAuth2 token as a POST parameter:
uri.query = URI.encode_www_form(access_token: 'YOUR_OAUTH_TOKEN')
# Encoding really isn't necessary though for this though, so this should suffice
uri.query = 'access_token=YOUR_OAUTH_TOKEN'

MtGox price ticker through Ruby

This should be simple, given the public nature of the data, but for some reason my Ruby script is timing out on making the request.
The URL is http://mtgox.com/api/1/BTCGBP/ticker - works fine in browsers, and returns the expected JSON.
require 'net/https'
require 'uri'
uri = URI.parse('https://mtgox.com/api/1/BTCGBP/ticker')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true if uri.scheme == 'https'
resp, response = http.post(uri.request_uri, nil)
This, however, returns the Timeout::Error: execution expired exception (every time) from the same box. I'm probably missing something really obvious; can anyone help?
Thanks
I tried your code in my environment and everything was ok. Can you write something more about this error, in which line it happened etc. ?
And are you sure to use POST verb (RESTful) ? What do you want to do ? I modified your code:
require 'net/https'
require 'uri'
uri = URI.parse('https://mtgox.com/api/1/BTCGBP/ticker')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true if uri.scheme == 'https'
resp = http.get(uri.request_uri)
puts resp.body
I use GET verb and I got JSON.

Net::HTTP::Put.new(url.path) shows the 401 error in RUby

HI ,
i am new to ROR
i am writing Ruby code for calling API blogs
i have written ruby code for
Creating the blog by
require 'net/http'
require 'uri'
url = URI.parse('http://localhost:3000/api/blogs/create.xml')
req = Net::HTTP::Post.new(url.path)
req.basic_auth 'a', 'a'
req.set_form_data({'blogpost[title]'=>'TestingAPIBlogposttitle',
'blogpost[description]'=>'Testing api desc',
'blogpost[category_id]'=>'3121'}, ';')
res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req)}
case res
when Net::HTTPSuccess, Net::HTTPRedirection
puts res.body
else
res.error!
end
which runs successfully by creating a new blog
And i have a search code
require 'net/http'
require 'uri'
require 'cgi'
## Change this part according to the api to be accessed and the params to be passed.
uri = URI.parse( "http://localhost:3000/api/blogs/show/blogtitle.xml" )
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Get.new(uri.path)
request.basic_auth 'a', 'a'
response = http.request(request)
puts response.body
which returns the
<?xml version="1.0" encoding="UTF-8"?>
<blogpost>
<created-at type="datetime">2010-09-02T08:18:22Z</created-at>
<description><p>Blog desc</p></description>
<slug>blogtitle</slug>
<title>blogtitle</title>
<user>
<firstname>admin</firstname>
<lastname>k</lastname>
<login>admin</login>
</user>
</blogpost>
Now i am trying to Update a BLog
for this how to write the code
i tried by simply changing the POST.new by PUT.new
but it didnt works for me
its showing me the error even if i gave admin User credentials
It might be worth trying a POST request but also adding a _method = 'put' parameter to the request. Rails can simulate a PUT request in this way though I would expect it to respond correctly to an HTTP PUT too.

Resources