How to pass symbol as parameter of post request in ruby? - ruby

This code work well
Geokit::default_units = :miles #:kms, :nms, :meters
But this code make errors
puts params[:unit] # miles
Geokit::default_units = params[:unit] #:miles, :kms, :nms, :meters
What is wrong with this?

That's because all that goes through the params is an string, if you want a symbol, then consider using .to_sym:
params = { unit: 'miles' }
p params[:unit].class # String
p params[:unit].to_sym.class # Symbol

have you confirmed that params[:unit] is actually a symbol, and not a string?
Geokit::default_units = params[:unit].to_sym
If the above solves your problem, then you didn't have a symbol in there to start with (likely, if params has been read from an HTTP request)

Related

Get answer from Google Dictionary API using ruby win Portuguese and accented characters

I'm trying to get results from the Google Dictionary API with ruby. It works well with non accented characters but does not work with accented characters (i.e. if you type directly the URL into the address bar of the browser).
If you use the chrome browser you get good answers either with accents or no accents.
I already jumped over the problem of the URI parser not linking URLs with accents using the following code
require "addressable"
require "net/http"
begin
uri = Addressable::URI.convert_path('https://api.dictionaryapi.dev/api/v2/entries/pt-BR/há')
p uri
rescue => error
p error
end
response = Net::HTTP.get(uri)
p response
I get an empty response, while using the browser I get the correct response.
Can somebody suggest some workaround? What am I doing wrong?
I didn't dig deep inside addressable gem.
But here is a working example with URI and JSON:
require "net/http"
require "json"
begin
uri = URI.parse(URI.encode('https://api.dictionaryapi.dev/api/v2/entries/pt-BR/há'))
p uri
rescue => error
p error
end
response = Net::HTTP.get(uri)
p JSON.parse(response)
=>
[
{
"word"=>"ha",
"phonetics"=>[{}],
"meanings"=>[
{
"partOfSpeech"=>"undefined",
"definitions"=>[{"definition"=>"símb. de HECTARE.", "synonyms"=>[], "antonyms"=>[]}]}
]
},
{
"word"=>"hã",
"phonetics"=>[{}],
"origin"=>"⊙ ETIM voc.onom.",
"meanings"=>[
{
"partOfSpeech"=>"interjeição",
"definitions"=>[
{
"definition"=>"expressa reflexão, esclarecimento, admiração.", "synonyms"=>[], "antonyms"=>[]
}
]
}
]
}
]
Thx for all your answers so far but it seems that the problem is on the API (that is no longer maintained by Google).
What is happening in your last example with that the word 'hà' is transformed in 'ha' i.e the accent is removed and the semantics are lost.
I will try another way.

Ruby URI - How to get entire path after URL

How do you get the full path of the URL given the following
uri = URI("http://foo.com/posts?id=30&limit=5#time=1305298413")
I just want posts?id=30&limit=5#time=1305298413
I tried uri.path and that returns /posts and ui.query returns 'id=30&limit=5'
The method you are looking for is request_uri
uri.request_uri
=> "/posts?id=30&limit=5"
You can use any method you'd like to remove the leading / if needed.
Edit: To get the part after the # sign, use fragment:
[uri.request_uri, uri.fragment].join("#")
=> "/posts?id=30&limit=5#time=1305298413"
You can ask the URI object for its path, query, and fragment like this:
"#{uri.path}?#{uri.query}##{uri.fragment}"
# => "/posts?id=30&limit=5#time=1305298413"
or (a little more consice, but less explicit):
"#{uri.request_uri}##{uri.fragment}"
# => "/posts?id=30&limit=5#time=1305298413"
A bit of an artsy solution, for completeness – others may be more reasonable :)
uri.dup.tap { _1.scheme = _1.user = _1.password = _1.host = _1.port = nil }.to_s
Though a benefit of this solution is that it also handles URI::Generic like you'd get from parsing a standalone path:
uri = URI.parse("/foo?bar#baz") # => #<URI::Generic /foo?bar#baz>
Solutions that rely on URI::HTTP#request_uri won't work with URI::Generic. So if you're writing code that accepts both full URLs and paths, that may be a factor.
File.basename("http://foo.com/posts?id=30&limit=5#time=1305298413")
# => "posts?id=30&limit=5#time=1305298413"

Ruby httpclient: 'create_request': undefined method 'each'

I'm green when it comes to Ruby. Right now I'm mucking about with a script which connects to the Terremark eCloud API Explorer. I'm trying to use the httpclient gem, but I'm a bit confused as to how I'm supposed to construct my client.
#!/usr/bin/ruby
require "httpclient"
require 'base64'
require 'hmac-sha1'
require 'openssl'
# Method definitions
def get_date
# Get the time and date in the necessary format
result = Time.now.strftime('%a, %d %b %Y %H:%M:%S GMT')
end
def get_signature(action,date,headers,resource,user,pass)
string_to_sign = "#{action}
#{date}
#{headers}
#{resource}\n"
return Base64.encode64(OpenSSL::HMAC.digest('sha1', "#{user}:#{pass}", "#{string_to_sign}"))
end
# Initial variables
date = get_date
domain = "https://services.enterprisecloud.terremark.com"
password = 'password'
query = {}
tmrk_headers = Hash.new
tmrk_headers['x-tmrk-date: '] = date
tmrk_headers['x-tmrk-version: '] = '2013-06-01'
uri = '/cloudapi/spec/networks/environments/1'
url = "#{domain}#{uri}"
username = 'user#terremark.com'
verb = 'GET'
signature = get_signature(verb,date,tmrk_headers,uri,username,password)
tmrk_headers['Authorization: '] = "Basic \"#{signature}\""
puts signature
client = HTTPClient.new
client.get_content(url,query,tmrk_headers)
EDIT: This is no longer valid as I've moved beyond this error with some help:
Right now I'm not concerned about seeing what is returned from the connection. I'm just looking to create an error-free run. For instance, if I run the script without the client.get_content line it will return to a prompt without issue (giving me the impression that everything ran cleanly, if not uselessly).
How am I supposed to construct this? The httpclient documentation uses the example with external headers:
extheader = [['Accept', 'image/jpeg'], ['Accept', 'image/png']]
clnt.get_content(uri, query, extheader)
I'm making the assumption that the query is the URI that I've defined.
In all reality, it isn't set up right in the first place. I need to be able to include the string in the auth_header variable in the string to be signed but the signature is actually part of the variable. I've obviously created a hole in that regard.
Any assistance with this will be more than appreciated.
EDIT2: Removed strace pastebin. Adding Ruby backtrace:
/home/msnyder/.rvm/gems/ruby-2.1.1/gems/httpclient-2.3.4.1/lib/httpclient.rb:1023:in `create_request': undefined method `each' for #<String:0x0000000207d1e8> (NoMethodError)
from /home/msnyder/.rvm/gems/ruby-2.1.1/gems/httpclient-2.3.4.1/lib/httpclient.rb:884:in `do_request'
from /home/msnyder/.rvm/gems/ruby-2.1.1/gems/httpclient-2.3.4.1/lib/httpclient.rb:959:in `follow_redirect'
from /home/msnyder/.rvm/gems/ruby-2.1.1/gems/httpclient-2.3.4.1/lib/httpclient.rb:594:in `get_content'
from ./test.rb:42:in `<main>'
EDIT3: Updated script; adding further backtrace after making necessary script modifications:
/
home/msnyder/.rvm/gems/ruby-2.1.1/gems/httpclient-2.3.4.1/lib/httpclient.rb:975:in `success_content': unexpected response: #<HTTP::Message::Headers:0x00000001dddc58 #http_version="1.1", #body_size=0, #chunked=false, #request_method="GET", #request_uri=#<URI::HTTPS:0x00000001ddecc0 URL:https://services.enterprisecloud.terremark.com/cloudapi/spec/networks/environments/1>, #request_query={}, #request_absolute_uri=nil, #status_code=400, #reason_phrase="Bad Request", #body_type=nil, #body_charset=nil, #body_date=nil, #body_encoding=#<Encoding:US-ASCII>, #is_request=false, #header_item=[["Content-Type", "text/html; charset=us-ascii"], ["Server", "Microsoft-HTTPAPI/2.0"], ["Date", "Thu, 27 Mar 2014 23:12:53 GMT"], ["Connection", "close"], ["Content-Length", "339"]], #dumped=false> (HTTPClient::BadResponseError)
from /home/msnyder/.rvm/gems/ruby-2.1.1/gems/httpclient-2.3.4.1/lib/httpclient.rb:594:in `get_content'
from ./test.rb:52:in `<main>'
The issue that you're having as stated by your backtrace
/home/msnyder/.rvm/gems/ruby-2.1.1/gems/httpclient-2.3.4.1/lib/httpclient.rb:1023:in `create_request': undefined method `each' for #<String:0x0000000207d1e8> (NoMethodError)
from /home/msnyder/.rvm/gems/ruby-2.1.1/gems/httpclient-2.3.4.1/lib/httpclient.rb:884:in `do_request'
from /home/msnyder/.rvm/gems/ruby-2.1.1/gems/httpclient-2.3.4.1/lib/httpclient.rb:959:in `follow_redirect'
from /home/msnyder/.rvm/gems/ruby-2.1.1/gems/httpclient-2.3.4.1/lib/httpclient.rb:594:in `get_content'
from ./test.rb:42:in `<main>'
is that it seems like you're passing a String object to one of the arguments in get_content where it expects an object that responds to the method each.
From looking at the documentation of httpclient#get_content http://www.ruby-doc.org/gems/docs/h/httpclient-xaop-2.1.6/HTTPClient.html#method-i-get_content
It expects the second parameter to be a Hash or Array of arguments
From your code sample and showing only the relevant parts
uri = '/cloudapi/spec/networks/environments/1'
url = "https://services.enterprisecloud.terremark.com"
tmrk_headers = "x-tmrk-date:\"#{date}\"\nx-tmrk-version:2014-01-01"
auth_header = "Authorization: CloudApi AccessKey=\"#{access_key}\" SignatureType=\"HmacSHA1\" Signature=\"#{signature}\""
full_header = "#{tmrk_headers}\n#{auth_header}"
client = HTTPClient.new
client.get_content(url,uri,full_header)
There are two things that I see wrong with your code.
You're passing in a String value for the query. Specifically, you're passing in uri which has a value of what I'm assuming is the path that you want to hit.
For the extra headers parameter, you're passing in a String value which is in the full_header
What you need to do in order to fix this is pass in the full url for the first parameter.
This means it should look something like this:
url = "https://services.enterprisecloud.terremark.com/cloudapi/spec/networks/environments/1"
query = {} # if you have any parameters to pass in they should be here.
headers = {
"x-tmrk-date" => date, "x-tmrk-version" => "2014-01-01",
"Authorization" => "CloudApi AccessKey=#{access_key} SignatureType=HmacSHA1 Signature=#{signature}"
}
client = HTTPClient.new
client.get_content(url, query, headers)

I am trying to use Curl::Easy.http_put but have some issues with the data argument

I'm struggling with a ruby script to upload some pictures to moodstocks using their http interface
here is the code that I have so far
curb = Curl::Easy.new
curb.http_auth_types = :digest
curb.username = MS_API
curb.password = MS_SECRET
curb.multipart_form_post = true
Dir.foreach(images_directory) do |image|
if image.include? '.jpg'
path = images_directory + image
filename = File.basename(path, File.extname(path))
puts "Upload #{path} with id #{filename}"
raw_url = 'http://api.moodstocks.com/v2/ref/' + filename
encoded_url = URI.parse URI.encode raw_url
curb.url = encoded_url
curb.http_put(Curl::PostField.file('image_file', path))
end
end
and this is the error that I get
/Library/Ruby/Gems/2.0.0/gems/curb-0.8.5/lib/curl/easy.rb:57:in `add': no implicit conversion of nil into String (TypeError)
from /Library/Ruby/Gems/2.0.0/gems/curb-0.8.5/lib/curl/easy.rb:57:in `perform'
from upload_moodstocks.rb:37:in `http_put'
from upload_moodstocks.rb:37:in `block in <main>'
from upload_moodstocks.rb:22:in `foreach'
from upload_moodstocks.rb:22:in `<main>'
I think the problem is in how I give the argument to the http_put method, but I have tried to look for some examples of Curl::Easy.http_put and have found nothing so far.
Could anyone point me to some documentation regarding it or help me out on this.
Thank you in advance
There are several problems here:
1. URI::HTTP instead of String
First, the TypeError you encounter comes from the fact that you pass a URI::HTTP instance (encoded_url) as curb.url instead of a plain Ruby string.
You may want to use encoded_url.to_s, but the question is why do you do this parse/encode here?
2. PUT w/ multipart/form-data
The second problem is related to curb. At the time of writing (v0.8.5) curb does NOT support the ability to perform a HTTP PUT request with multipart/form-data encoding.
If you refer to the source code you can see that:
the multipart_form_post setting is only used for POST requests,
the put_data setter does not support Curl::PostField-s
To solve your problem you need an HTTP client library that can combine Digest Authentication, multipart/form-data and HTTP PUT.
In Ruby you can use rufus-verbs, but you will need to use rest-client to build the multipart body.
There is also HTTParty but it has issues with Digest Auth.
That is why I greatly recommend to go ahead with Python and use Requests:
import requests
from requests.auth import HTTPDigestAuth
import os
MS_API_KEY = "kEy"
MS_API_SECRET = "s3cr3t"
filename = "sample.jpg"
with open(filename, "r") as f:
base = os.path.basename(filename)
uid = os.path.splitext(base)[0]
r = requests.put(
"http://api.moodstocks.com/v2/ref/%s" % uid,
auth = HTTPDigestAuth(MS_API_KEY, MS_API_SECRET),
files = {"image_file": (base, f.read())}
)
print(r.status_code)

Ruby regular express. detect wrong email address such as "hi#myio..io"

To detect wrong email address such as "hi#myio..io"
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
VALID_EMAIL_REGEX_FULL = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
First one fails. Second suceeds.
I don't understand how does this part make it different? (\.[a-z]+)*\.[a-z]
Thank you!
The better answer is that using a regular expression for matching email addresses is a bad idea. For one, all valid addresses are not active. hd1#jsc.d8u.us is me, hd2#jsc.d8u.us is a valid email address by every RFC in existence, but it's not an active email account.
If you want to do email address validation, you could do worse than to set up a web service that does nothing more than take a string, use JavaMail's address parsing (InternetAddress.parse()), which throws an exception if the parse fails and returns the address if it succeeds. Sample code below:
public class ValidationServlet extends HttpServlet {
protected void doHead(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String candid8Address = request.getParameter("email");
try {
InternetAddress.parse(candid8Address);
response.setStatus(HttpServletResponse.SC_OK);
} catch (AddressException e) {
response.setStatus(HttpServletResponse.SC_NOT_FORBIDDEN);
}
}
}
Let me know if you need further assistance...
In the first one #[a-z\d\-.] has . which matches with any character including an .. It should be removed so the domain will only match a alphanumeric character. It should be:
/\A[\w+\-.]+#[a-z\d\-]+\.[a-z]+\z/i
Try this :
/^([\w.%+-]+)#([\w-]+.)+([\w]{2,})$/i
To validate the email address
Try the following:--
/\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
I once found this one:
# RFC822 Email Address Regexp
# ---------------------------
#
# Originally written by Cal Henderson
# c.f. http://iamcal.com/publish/articles/php/parsing_email/
#
# Translated to Ruby by Tim Fletcher, with changes suggested by Dan Kubb.
#
# Licensed under a Creative Commons Attribution-ShareAlike 2.5 License
# http://creativecommons.org/licenses/by-sa/2.5/
#
# (see: http://tfletcher.com/lib/rfc822.rb)
RFC822 = begin
qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]'
dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]'
atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-' +
'\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+'
quoted_pair = '\\x5c[\\x00-\\x7f]'
domain_literal = "\\x5b(?:#{dtext}|#{quoted_pair})*\\x5d"
quoted_string = "\\x22(?:#{qtext}|#{quoted_pair})*\\x22"
domain_ref = atom
sub_domain = "(?:#{domain_ref}|#{domain_literal})"
word = "(?:#{atom}|#{quoted_string})"
domain = "#{sub_domain}(?:\\x2e#{sub_domain})*"
local_part = "#{word}(?:\\x2e#{word})*"
# The following line was needed to change for ruby 1.9
# was: addr_spec = "#{local_part}\\x40#{domain}"
addr_spec = Regexp.new("#{local_part}\\x40#{domain}", nil, 'n')
pattern = /\A#{addr_spec}\z/
end.freeze

Resources