Let's say I have a string like:
url = "https://example.com/user/tr_auth.php?key=34432&cmp_id=344&tr_id={user_id}"
I want to update the cmp_id=344 to be say cmp_id=44553. What's the best way to accomplish this? I can't gsub per say because I don't know what cmp_id might be equal, only that it will be a URL parameter in the string.
It seems like I want to do something like
uri = URI.parse(url)
params = CGI.parse(uri.query)
But then, how do I re-build the string swapping out the cmp_id parameter to be 44553?
Thanks!
If you are dealing with a web application (and/or Rails as the tag seems to indicate), then you certainly have Rack available. Rack::Utils has methods to parse and build a query.
url = "https://example.com/user/tr_auth.php?key=34432&cmp_id=344&tr_id={user_id}"
uri = URI.parse(url)
query = Rack::Utils.parse_query(uri.query)
# => {"key"=>"34432", "cmp_id"=>"344", "tr_id"=>"{user_id}"}
# Replace the value
query["cmp_id"] = 44553
uri.query = Rack::Utils.build_query(query)
uri.to_s
# => "https://example.com/user/tr_auth.php?key=34432&cmp_id=44553&tr_id=%7Buser_id%7D"
Also note that Rack, by default, escapes the query.
url = "https://example.com/user/tr_auth.php?key=34432&cmp_id=344&tr_id={user_id}"
uri = URI.parse(url)
params = CGI.parse(uri.query)
params['cmp_id'] = 44553
new_str = uri.host + uri.path + '?' + params.to_query
First, you can parse the url for params:
require 'cgi'
url = 'https://example.com/user/tr_auth.php?key=34432&cmp_id=344&tr_id={user_id}'
string_params = url.split('?')[1]
hash = CGI::parse(string_params)
Then you can iterate the hash by keys and change values:
hash.keys.each {|key| hash[key]='new value'}
url_params = hash.to_param
Related
I have some issues with caching in rails. I don't find how should i setting it.
Here's the code :
submit_key = nil
pairs_email = Hash.new
pairs_type = Rails.cache.fetch("cache_typeform", :expires_in => 1.day) do
(0..9).each do
if submit_key.present?
url = "https://api.typeform.com/forms/#{typeform_id}/responses?page_size=1000&until=#{submit_key}"
response = RestClient.get url, {:Authorization => 'Bearer XXXXXXXXXXX'}
parsed = JSON.parse(response.body)
else
response = RestClient.get "https://api.typeform.com/forms/#{typeform_id}/responses?page_size=1000", {:Authorization => 'Bearer XXXXXXXXXXXXXXX}
parsed = JSON.parse(response.body)
end
parsed['items'].each do |item|
pairs_email[item['hidden']['email']] = item['token'] if item['hidden']['email'].present?
end
submit_key = parsed['items'][-1]['submitted_at'].chop
end
end
Then it should return a pairs containing an email and an ID and this pairs is used after to get more informations. However, nothing is returning.
Does someone can tell me what I've done wrong in my code? Am I missing something somewhere?
UPDATE
I want to use my cache for getting informations from the typeform API :
results = Hash.new
if pairs_email[email].present?
url = "https://api.typeform.com/v1/form/#{typeform_id}?key=#{ENV['TYPEFORM_API_KEY']}&token=#{pairs_email[email]}"
response = RestClient.get(url)
parsed = JSON.parse(response.body)
results["email"] = parsed["responses"][0]["hidden"]["email"] # Email
results["first_name"] = parsed["responses"][0]["answers"]["textfield_25078009"] # prénom
results["last_name"] = parsed["responses"][0]["answers"]["textfield_25078014"] # nom
results["phone_number"] = parsed["responses"][0]["answers"]["textfield_25444504"] #N°
results["job"] = parsed["responses"][0]["answers"]["textfield_24904749"] # métier
results["status_legal"] = parsed["responses"][0]["answers"]["list_24904751_choice"] # statut légal ?
results["birthdate"] = parsed["responses"][0]["answers"]["date_24904754"] # Date de naissance
results["zipcode"] = parsed["responses"][0]["answers"]["number_24904755"] # Code postal
results["has_partner"] = parsed["responses"][0]["answers"]["yesno_53894471"] # has_partner
results["children"] = parsed["responses"][0]["answers"]["list_53894494_choice"] # Nombre d'enfants
results["optical_option"] = parsed["responses"][0]["answers"]["list_24904752_choice_32209601"] # optical_option
results["dental_option"] = parsed["responses"][0]["answers"]["list_24904752_choice_32209602"] # dental_option
results["sick_15d"] = parsed["responses"][0]["answers"]["list_24904752_choice_32209603"] # Sick_15d
results["target_year"] = parsed["responses"][0]["answers"]["list_24905736_choice"] # target_year
results["monthly_income"] = parsed["responses"][0]["answers"]["number_24904756"] # monthly_income
results["independent"] = parsed["responses"][0]["answers"]["yesno_53895024"] # independent_1_year
#results["subject_to_discuss"] = parsed["responses"][0]["answers"]["textarea_24904759"] # Avez-vous des sujets dont vous voulez discuter
end
Here's something you must try before getting caching right. Attaching a screenshot from my machine.
Also if you are in development environment you would need to enable caching to see the effect. You could add config.action_controller.perform_caching = true and config.cache_store = :memory_store, { size: 64.megabytes } to your development.rb config file to enable caching.
This is just an idea of how caching happens and check if it really works, this should help you get going with your task.
Rails.cache.fetch stores the value evaluated from the block passed into this method (if there is one, of course). In your example, you're returning (0..9) range from the block, instead of actually evaluated [email id] pairs.
I am using Net::HTTP::Post to send a request to a pre-determined url, like so:
my_url = '/path/to/static/url'
my_string_parameter = 'objectName=objectInfo'
my_other_string_parameter = 'otherObjectName=otherObjectInfo'
request = Net::HTTP::Post.new(my_url)
request.body = my_string_parameter
However, I know that my_url expects two string parameters. I have both parameters ready (they're statically generated) to be passed in. Is there a way to pass in multiple strings - both my_string_parameter as well as my_other_string_parameter to a post request via Ruby on Rails?
EDIT: for clarity's sake, I'm going to re-explain everything in a more organized fashion. Basically, what I have is
my_url = 'path/to/static/url'
# POST requests made to this url require 2 string parameters,
# required_1 and required_2
param1 = 'required_1=' + 'param1_value'
param2 = 'requred_2=' + 'param2_value'
request = request.NET::HTTP::Post.new(my_url)
If I try request.body = param1, then as expected I get an error saying "Required String parameter 'required_2' is not present". Same with request.body=param2, the same error pops up saying 'required_1' is not present. I'm wondering if there is a way to pass in BOTH parameters to request.body? Or something similar?
Try this.
uri = URI('http://www.example.com')
req = Net::HTTP::Post.new(uri)
req.set_form_data('param1' => 'data1', 'param2' => 'data2')
Alternative
uri = URI('http://www.example.com/')
res = Net::HTTP.post_form(uri, 'param1' => 'data1', 'param2' => 'data2')
puts res.body
For more request like Get or Patch you can refer This offical doc.
You can send it like this.
data = {'params' => ['parameter1', 'parameter2']}
request = Net::HTTP::Post.new(my_url)
request.set_form_data(data)
If your params are string:
url = '/path/to/controller_method'
my_string_parameter = 'objectName=objectInfo'
my_other_string_parameter = 'otherObjectName=otherObjectInfo'
url_with_params = "#{url}?#{[my_string_parameter, my_other_string_parameter].join('&')}"
request = Net::HTTP::Post.new(url_with_params)
If your params are hash It would be easier
your_params = {
'objectName' => 'objectInfo',
'otherObjectName' => 'otherObjectInfo'
}
url = '/path/to/controller_method'
url_with_params = "#{url}?#{your_params.to_query}"
request = Net::HTTP::Post.new(url_with_params)
I'm working on building a small script that searches for the 5 most recent pictures tweeted by a service, isolates the URL and puts that URL into an array.
def grabTweets(linkArray) #brings in empty array
tweets = Twitter.search("[pic] "+" url.com/r/", :rpp => 2, :result_type => "recent").map do |status|
tweets = "#{status.text}" #class = string
url_regexp = /http:\/\/\w/ #isolates link
url = tweets.split.grep(url_regexp).to_s #chops off link, turns link to string from an array
#add link to url array
#print linkArray #prints []
linkArray.push(url)
print linkArray
end
end
x = []
timelineTweets = grabTweets(x)
The function is returning things like this: ["[\"http://t.co/6789\"]"]["[\"http://t.co/12345\"]"]
I'm trying to get it to return ["http://t.co/6789", "http://t.co/1245"] but it's not managing that.
Any help here would be appreciated. I'm not sure what I'm doing wrong.
The easiest way to grab URLs in Ruby is to use the URI::extract method. It's a pre-existing wheel that works:
require 'uri'
require 'open-uri'
body = open('http://www.example.com').read
urls = URI::extract(body)
puts urls
Which returns:
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
http://www.w3.org/1999/xhtml
http://www.icann.org/
mailto:iana#iana.org?subject=General%20website%20feedback
Once you have the array you can filter for what you want, or you can give it a list of schemes to extract.
To strip a url out a string and push into urls array, you can do:
urls = []
if mystring =~ /(http:\/\/[^\s]+)/
urls << $1
end
grep returns an array:
grep(pattern) → array
grep(pattern) {| obj | block } → array
Returns an array of every element in enum for which Pattern === element.
So your odd output is coming from the to_s call the follows your grep. You're probably looking for this:
linkArray += tweets.split.grep(url_regexp)
or if you only want the first URL:
url = tweets.split.grep(url_regexp).first
linkArray << url if(url)
You could also skip the split.grep and use scan:
# \S+ should be good enough for this sort of thing.
linkArray += tweets.scan(%r{https?://\S+})
# or
url = tweets.scan(%r{https?://\S+}).first
linkArray << url if(url)
How can I parse urls like
http://www.1800contacts.com/productlist.aspx?dl=P&source=cj&ac=8.2.0007
and only get
http://www.1800contacts.com
?
PS. Some urls have subdomains etc so I can't use regexps here.
Try to use 'uri' library:
require 'uri'
address = 'http://www.1800contacts.com/productlist.aspx?dl=P&source=cj&ac=8.2.0007'
uri = URI.parse(address)
puts "#{uri.scheme}://#{uri.host}" # => http://www.1800contacts.com
I like #skojin's answer number 1 (sorry I opened another answer, it's only a long comment) because it makes more general code for both cases:
require 'uri'
uri = URI "http://www.1800contacts.com/productlist.aspx?dl=P&source=cj&ac=8.2.0007"
uri.query = uri.fragment = nil
uri.path = ""
uri.to_s
# => "http://www.1800contacts.com"
uri = URI "http://example.com:8080/you-found-me.php"
uri.query = uri.fragment = nil
uri.path = ""
uri.to_s
# => "http://example.com:8080"
2 alternative ways
uri = URI.parse(url); uri.path = ''; uri.query = nil; uri.to_s
url.split('/')[0,3].join('/')
I'm trying to make a request to a web service (fwix), and in my rails app I've created the following initializer, which works... sorta, I have two problems however:
For some reason the values of the parameters need to have +'s as the spaces, is this a standard thing that I can accomplish with ruby? Additionally is this a standard way to form a url? I thought that spaces were %20.
In my code how can I take any of the options sent in and just use them instead of having to state each one like query_items << "api_key=#{options[:api_key]}" if options[:api_key]
The following is my code, the trouble area I'm having are the lines starting with query_items for each parameter in the last method, any ideas would be awesome!
require 'httparty'
module Fwix
class API
include HTTParty
class JSONParser < HTTParty::Parser
def json
JSON.parse(body)
end
end
parser JSONParser
base_uri "http://geoapi.fwix.com"
def self.query(options = {})
begin
query_url = query_url(options)
puts "querying: #{base_uri}#{query_url}"
response = get( query_url )
rescue
raise "Connection to Fwix API failed" if response.nil?
end
end
def self.query_url(input_options = {})
#defaults ||= {
:api_key => "my_api_key",
}
options = #defaults.merge(input_options)
query_url = "/content.json?"
query_items = []
query_items << "api_key=#{options[:api_key]}" if options[:api_key]
query_items << "province=#{options[:province]}" if options[:province]
query_items << "city=#{options[:city]}" if options[:city]
query_items << "address=#{options[:address]}" if options[:address]
query_url += query_items.join('&')
query_url
end
end
end
For 1)
You API provider is expecting '+' because the API is expecting in a CGI formatted string instead of URL formatted string.
require 'cgi'
my_query = "hel lo"
CGI.escape(my_query)
this should give you
"hel+lo"
as you expect
for Question 2) I would do something like
query_items = options.keys.collect { |key| "#{key.to_s}=#{options[key]}" }
def self.query_url(input_options = {})
options = {
:api_key => "my_api_key",
}.merge(input_options)
query_url = "/content.json?"
query_items = []
options.each { |k, v| query_items << "#{k}=#{v.gsub(/\s/, '+')}" }
query_url += query_items.join('&')
end
I'm a developer at Fwix and wanted to help you with your url escaping issue. However, escaping with %20 works for me:
wget 'http://geoapi.fwix.com/content.xml?api_key=mark&province=ca&city=san%20francisco&query=gavin%20newsom'
I was hoping you could provide me with the specific request you're making that you're unable to escape with %20.