escape comma in ruby URI::HTTP library - ruby-on-rails

I'm using URI::HTTP library to build a URL I need to use to send to an endpoint.
ids = "12345,54504"
uri = URI::HTTP.build({
:host => HOST,
:path => '/endpoint',
:query => {
:ids => ids
}.to_query,
})
The issue I am having is that the endpoint is expecting ids to be comma-separated. However, the URL that this builds replaces the comma with %2C. How do I get the url to just send the comma and not encode it.

Don't worry the %2C is the URL-encoded of the comma.
You can try to create a route in your rails application and puts params[:ids], you will see your ids with the coma.

Related

Remove slash from string in ruby on rails

I need to remove "\" from below string
{\"MACAddress\":\"74:5E:78\",\"DeviceName\":\"Connected_Device\"}
Response should be
{"MACAddress":"74:5E:78","DeviceName":"Connected_Device"}
I need to check if string includes "\n",i need to add validation to remove "\"
Can you please help how to handle this in rails?
Currently i am using httpparty below code
reqType = params['reqType']
payLoadData = params['payLoadData']
p "PAYLOAD DATA-------------- #{payLoadData}"
if reqType == "post"
start = Time.now
url=params['url']
body_param= device
p "payLoadData-------------- #{body_param}"
response = HTTParty.post(url,
:body => body_param,
:headers => {'Content-Type' => 'application/json','User-Agent'=> 'Auto',"Authorization" => 'Basic=='})
result_hash["response"].push({"body": response.body.to_s, "response_time": response_time.to_s})
result_hash["status"].push(response.code)
JSON.parse("{\"MACAddress\":\"74:5E:78\",\"DeviceName\":\"Connected_Device\"}")
It should do the trick
The response that you get from your Ajax call is a hash in JSON format.
Just use a JSON parser to translate the JSON string into a Ruby hash:
require 'json'
pay_load = params['payLoadData']
device = JSON.parse(pay_load)
device['MACAddress']
#=> "74:5E:78"
device['DeviceName']
#=> "Connected_Device"
When you just want to output the hash a simple puts device or a <%= device %> (depending on your context) should work. Because in both cases to_s is called on the hash internally.

Encoding parameters with multiple duplicate keys

I seem to be having the same problem as this chap here
I want to encode some parameters (for the import.io api). Effectively:
params = {
:input => "webpage/url:http://www.example.com",
:input => "keywords:some+keywords"
}
But that won't work, so I think this is the right approach:
params = { :input => ["webpage/url:http://www.example.com", "keywords:some+keywords"] }
and I want it to output
params.to_query
=> "input=webpage%2Furl%3Ahttp%3A%2F%2Fwww.example.com%2Fsome-id&input=keywords%3Asome%2Bkeywords"
unfortunately, I get
"input%5B%5D=webpage%2Furl%3Ahttp%3A%2F%2Fwww.example.com%2Fsome-id&input%5B%5D=keywords%3Asome%2Bkeywords"
It's adding [] after the input, which I believe is standard behaviour. How can I stop it doing it?
To clarify, what is the ruby or 'rails way' of dealing with url parameters that require duplicate keys?
Ran into a similar issue, there's a helpful post here Ruby Hash with duplicate keys? but briefly
params = {}.compare_by_identity
params['input'] = "webpage/url:http://www.example.com"
params['input'.dup] = "keywords:some+keywords"
then
params.to_query
returns
"input=keywords%3Asome%2Bkeywords&input=webpage%2Furl%3Ahttp%3A%2F%2Fwww.example.com"
Some characters in a url have special importance to the processing of the url: they are reserved, like keywords in a programming language. See Which characters make a URL invalid?
If you try to use these as the name or value of a parameter, it will break the uri and you'll get hard to predict results like you're seeing.
The answer is to URI escape the string, which will replace special characters with their encoded version. Rails will automatically unescape them when it gets the the request, so you don't need to worry about it.
You can escape them manually, but the best way, if you have them as a hash already, is to call .to_param on the hash.
params = { :input => ["webpage/url:http://www.example.com", "keywords:some+keywords"] }
=> {:input=>["webpage/url:http://www.example.com", "keywords:some+keywords"]}
params.to_param
=> "input%5B%5D=webpage%2Furl%3Ahttp%3A%2F%2Fwww.example.com&input%5B%5D=keywords%3Asome%2Bkeywords"

Rails Routing having a URL in the query string

So I need to hit a url like mydomain.com/proxies/www.msn.com in order to fulfill some ajax requests for an API
In my route I have
get "/proxies/:url" => "proxies#get"
and I in the controller I have
url_contents = Net::HTTP.get(URI.parse(params[:url]))
which if i put /proxies/www i get
undefined method `request_uri' for #<URI::Generic:0x3f89508 URL:www>
if i put /proxies/www.msn.com
I get
No route matches [GET] "/proxies/www.msn.com"
You have two separate problems here:
You're trying to treat a URL without a scheme as an HTTP URL.
Your /proxies route won't match :urls with dots and slashes the way you're expecting it to.
For the first one, you'll have to add the schema manually:
url = 'http://' + params[:url]
content = Net::HTTP.get(URI.parse(url))
For the second one, you can use a splat-route to deal with embedded slashes and :format => false to keep Rails from trying to treat .com, for example, as a format:
get '/proxies/*url' => 'proxies#get', :format => false
If you use :url, Rails will see embedded slashes as component separators and that's probably not what you want. Without the the :format => false, Rails will try to interpret .X (for any X) as a format (just like .html, .json, ...) rather than as part of the URL.
This is applicable for rails-2
The problem is with the dot(.) I guess. Ive tried something like below and it worked.
#routes.rb
map.get_proxy 'proxies/:url', :controller => "Proxies", :action => "get", :requirements => { :url => /.*/ }
#view file
#Here dot(.) are needed to replace with its encoded string %2E
<%= link_to 'Get The Site', get_proxy_url('www.msncom') %>
#Proxies Controller
#After receiving the url the %2E need to conovert to dot(.) again.
url_contents = Net::HTTP.get(URI.parse('http://'+params[:url]))
modified as stated by #mu.
match '/proxies/:url' => 'proxies#get', :as => :proxies_get

How do I encode the & symbol for batch requests?

I have a Facebook batch request that looks like this:
https://graph.facebook.com/?access_token=ACCESS_TOKEN&batch=[{"method": "GET", "relative_url": "search?q=EMAIL#ADDRESS.COM&type=user"}]
Sending this across the wire returns:
{"error"=>0, "error_description"=>"batch parameter must be a JSON array"}
If I remove the &type=user, it works fine (sends back an empty data array). I am absolutely certain that Facebook is not parsing the & character correctly. I read online somewhere that I could try encoding the & symbol to %26, however using that replacement seems to instead do a query for "EMAIL#ADDRESS.COM%26type=user". If you reverse the order of the parameters, you will see what I mean.
Any ideas how I can get the batch request parser on Facebook to recognize the & symbol without filing a bug report that will never be fixed?
EDIT:
I am using URI.encode. Here is the exact code:
queries = email_array.map { |email| { :method => "GET", :relative_url => "search?q=#{email}&type=user" } }
route = "https://graph.facebook.com/?access_token=#{token}&batch=#{URI.encode(queries.to_json)}"
res = HTTParty.post(route)
After actually playing around with this some more, I managed to reproduce the same behavior, even with a careful check and double-check that I was following the api specs correctly. This looks like a bug in facebook's batch method -- it doesn't understand ampersands in param values correctly.
Don't use a string literal to construct the json. Use to_json, like below. (Also, as an aside, don't use {} notation across more than one line, use do/end).
queries = []
email_array.each do |email|
queries << {:method => 'GET', :relative_url => "search?q=#{email}&type=user"}
end
route = "https://graph.facebook.com/?access_token=#{token}&batch=#{URI.encode(queries.to_json)}"
res = HTTParty.post(route)
Also, you can use Array#map to simply the code, like this:
queries = email_array.map { |email| {:method => 'GET', :relative_url => "search?q=#{email}&type=user"} }
route = "https://graph.facebook.com/?access_token=#{token}&batch=#{URI.encode(queries.to_json)}"
res = HTTParty.post(route)
EDIT: below is my original answer before the question was edited, for reference.
Try properly url encoding the whole parameter:
https://graph.facebook.com/?access_token=ACCESS_TOKEN&batch=[%7B%22method%22:%20%22GET%22,%20%22relative_url%22:%20%22search?q=EMAIL#ADDRESS.COM&type=user%22%7D]
In practice, you'd use URI.encode from the uri library to do this. Example:
irb(main):001:0> require 'uri'
=> true
irb(main):002:0> URI.encode('[{"method": "GET", "relative_url": "search?q=EMAIL#ADDRESS.COM&type=user"}]')
=> "[%7B%22method%22:%20%22GET%22,%20%22relative_url%22:%20%22search?q=EMAIL#ADDRESS.COM&type=user%22%7D]"
Or even better, use to_json to create your json string in the first place. Example:
irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'json'
=> true
irb(main):003:0> require 'uri'
=> true
irb(main):004:0> URI.encode([{:method => 'GET', :relative_url => 'search?q=EMAIL#ADDRESS.COM&type=user'}].to_json)
=> "[%7B%22method%22:%22GET%22,%22relative_url%22:%22search?q=EMAIL#ADDRESS.COM&type=user%22%7D]"
If this helps anyone, when my AdSet batch update failed because there was an "&" in one of the interests name:
{u'id': u'6003531450398', u'name': u'Dolce & Gabbana'}
I learned that the name can be anything, and as long as the id is correct, FB will populate the name itself.

How do I pass this param properly?

I want to make an API request with a text param, with information I currently have in params[:brand][:tag_list] which seems to be saved as a single comma-delimited string. What's the correct way to make the API request?
Controller code:
current_user.tag(#brand, :with => params[:brand][:tag_list], :on => :tags)
url = "http://www.viralheat.com/api/sentiment/review.json"
#sentiment_response = url.to_uri.get(
:api_key => 'MY_KEY',
:text => :tag_list ).deserialize #This is what I'm currently using and is wrong
Response codes from log:
<- (GET 49996946161 2204098100) http://www.viralheat.com:80/api/sentiment/review.json?api_key=MY_KEY&text=tag_list
-> (GET 49996946161 2204098100) 200 OK (62 bytes 3.09s)
Looking up the docs for viralheat, it looks like their api accepts exactly two parameters: api_key, and text. Assuming params[:brand][:tag_list] a comma-delimited string, you can form your request like so:
current_user.tag(#brand, :with => params[:brand][:tag_list], :on => :tags)
url = "http://www.viralheat.com/api/sentiment/review.json"
#sentiment_response = url.to_uri.get(
:api_key => 'MY_KEY',
:text => params[:brand][:tag_list].split(',').join('&') ).deserialize
This should create the url:
http://www.viralheat.com/api/sentiment/review.json?api_key=MY_KEY&text=cat%26dog%26​mouse
params[:brand][:tag_list].split(',') breaks your string into an array, and join('&') turns it back into a string, but this time delimited by ampersands (which seems to be what you want, based on what you said in a comment on your original post). Your uri.get method should escape the ampersands in the uri, which is why you see the %26s in the final url. This is correct.

Resources