Splitting response of Savon - ruby-on-rails

Somehow, the webservice I am using savon to deal with returns this response
{:do_deal_response=>{:do_deal_result=>"Code=000&CardNumber=0000&CardDate=12/18&PayDate=02/01/2017&BusinessName=בדיקות&Terminal=0962317010&ActionMethod=עסקה טלפונית&DealID=5349614&DealType=אשראי רגיל&DealTypeOut=עסקת חובה רגילה 0000000&OkNumber=0000000&DealDate=06/12/2016 11:00:14&PayNumber=&TotalSum=111&FirstPay=&CardName=ויזה כ.א.ל&CardNameID=2&AuthNum=0000000&DealNumber=06370507&ParamJ=J4&ErrorDesc=עסקה תקינה.&Currency=שקלים&CurrencyID=1&Manpik=ויזה כ.א.ל&ManpikID=2&Mutag=ויזה כ.א.ל&MutagID=2", :#xmlns=>"http://tempuri.org/"}}
accessing #response[:do_deal_response][:do_deal_result] obviously returns the string
"Code=000&CardNumber=0000&CardDate=12/18&PayDate=02/01/2017&BusinessName=בדיקות&Terminal=0962317010&ActionMethod=עסקה טלפונית&DealID=5349614&DealType=אשראי רגיל&DealTypeOut=עסקת חובה רגילה 0000000&OkNumber=0000000&DealDate=06/12/2016 11:00:14&PayNumber=&TotalSum=111&FirstPay=&CardName=ויזה כ.א.ל&CardNameID=2&AuthNum=0000000&DealNumber=06370507&ParamJ=J4&ErrorDesc=עסקה תקינה.&Currency=שקלים&CurrencyID=1&Manpik=ויזה כ.א.ל&ManpikID=2&Mutag=ויזה כ.א.ל&MutagID=2"
I want to be able to access this string as a hash with with symbols
like:
results[:code] = "000"

Instead of manually parsing, you can use the following:
require 'cgi'
parsed = CGI.parse(#response[:do_deal_response][:do_deal_result])
parsed['Code']
#=> ["000"]
Since this accepts multiple values for each key values are always wrapped in an array. If that bothers you, you can do one more transformation step with map (or map_values if you use Rails):
parsed.map { |k, v| [k.underscore.symbolize, v.size == 1 ? v.first : v] }.to_h
#=> => {:code=>"000", :card_number=>"0000", :ard_date=>"12/18", :pay_date=>"02/01/2017",...
This will only unwrap arrays with one element, everything else will stay in an array.

Stand-alone solution
This code could help you. It just splits the string around &, split every part around = and saves them as key and value in a Hash :
response = {:do_deal_response=>{:do_deal_result=>"Code=000&CardNumber=0000&CardDate=12/18&PayDate=02/01/2017&BusinessName=בדיקות&Terminal=0962317010&ActionMethod=עסקה טלפונית&DealID=5349614&DealType=אשראי רגיל&DealTypeOut=עסקת חובה רגילה 0000000&OkNumber=0000000&DealDate=06/12/2016 11:00:14&PayNumber=&TotalSum=111&FirstPay=&CardName=ויזה כ.א.ל&CardNameID=2&AuthNum=0000000&DealNumber=06370507&ParamJ=J4&ErrorDesc=עסקה תקינה.&Currency=שקלים&CurrencyID=1&Manpik=ויזה כ.א.ל&ManpikID=2&Mutag=ויזה כ.א.ל&MutagID=2", :#xmlns=>"http://tempuri.org/"}}
deal_result = response[:do_deal_response][:do_deal_result]
class String
def underscore
self.gsub(/::/, '/').
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
gsub(/([a-z\d])([A-Z])/,'\1_\2').
tr("-", "_").
downcase
end
end
results = deal_result.split('&').each_with_object({}) do |string, h|
key, value = string.split('=')
h[key.underscore.to_sym] = value
end
puts results
#=> {:code=>"000", :card_number=>"0000", :card_date=>"12/18", :pay_date=>"02/01/2017", :business_name=>"בדיקות", :terminal=>"0962317010", :action_method=>"עסקה טלפונית", :deal_id=>"5349614", :deal_type=>"אשראי רגיל", :deal_type_out=>"עסקת חובה רגילה 0000000", :ok_number=>"0000000", :deal_date=>"06/12/2016 11:00:14", :pay_number=>nil, :total_sum=>"111", :first_pay=>nil, :card_name=>"ויזה כ.א.ל", :card_name_id=>"2", :auth_num=>"0000000", :deal_number=>"06370507", :param_j=>"J4", :error_desc=>"עסקה תקינה.", :currency=>"שקלים", :currency_id=>"1", :manpik=>"ויזה כ.א.ל", :manpik_id=>"2", :mutag=>"ויזה כ.א.ל", :mutag_id=>"2"}
With Rack
If you have Rack installed :
require 'rack'
puts Rack::Utils.parse_nested_query(deal_result).map { |k, v| [k.underscore.to_sym, v] }.to_h
Both answers match exactly the structure you were looking for : snakecase symbol for key and non Array values.

Related

how to check if a certain key-value pair exists in array of hashes as json in ruby on rails

I have an array of hashes as json, so how to check my array of hashes contains a hash with a given key-value pair.
This is my json
[{"question"=>"0a2a3452", "answer"=>"bull"}, {"question"=>"58deacf9", "answer"=>"bullafolo"}, {"question"=>"32c53e5f", "answer"=>"curosit"}, {"question"=>"b5546bcf", "answer"=>""}, {"question"=>"0f0b314", "answer"=>""}]
I tried looping through the json array, but this is tedious, as I need to check that if that json has that hash with a given key-value pair
It's a questionnaire form, in which I have to perform an update on answers
if !#client_find.nil?
#client_find.questionnaire
params[:commit].each do |key, value|
#json=[]
#json = #client_find.questionnaire
if !value.empty? && #json.include?(key)
puts "blunderc "+ value.inspect
#new_append = Hash.new
#new_append[:question] = key
#new_append[:answer]= value
#json << #new_append
end
if !key.empty? && !value.empty?
#logic
#json.each do |u|
if (u.key? key)
puts "bothu "+ u[key].inspect
u[key] = value
end
end
end
end
Array#any? iterates through the array. In each iteration I check wether the current hash has the searched question key or not. If a hash is found Array#any? returns true otherwise false.
array = [{"question"=>"0a2a3452", "answer"=>"bull"}, {"question"=>"58deacf9", "answer"=>"bullafolo"}, {"question"=>"32c53e5f", "answer"=>"curosit"}, {"question"=>"b5546bcf", "answer"=>""}, {"question"=>"0f0b314", "answer"=>""}]
search_for_key = '0a2a3452'
array.any?{|hash| hash['question'] == search_for_key}
I'll assume that you want to check the existence of a hash which has the key/value pair "quesetion" => "some-value".
Here's how you can do it:
array.any? { |item| item['question'] == 'some-question-id' }
Considering your are checking for a particular key exists or not
#json.any? {|obj| obj.key?(your_particular_key)
You can filter the array using Enumerable#select to get only the hashes that contains the desired key.
filtered = my_hash.select { |item| item['desired_key'] }
That's possible because nil is falsey. If you input is a raw JSON you'll need to parse it to a Ruby hash using JSON#parse or any other equivalent method.
filtered will give you all the hashes that contain the desired_key.
Is that what you want ?
Btw guitarman's answer is way better !
questions = [{"question"=>"0a2a3452", "answer"=>"bull"}, {"question"=>"58deacf9", "answer"=>"bullafolo"}, {"question"=>"32c53e5f", "answer"=>"curosit"}, {"question"=>"b5546bcf", "answer"=>""}, {"question"=>"0f0b314", "answer"=>""}]
result = questions.find { |question| question['question'] == "Bonour" }
if result.nil?
puts "Not found"
else
puts "#{result['question']} #{result['answer']}"
end

map array with condition

I have array like
strings = ["by_product[]=1", "by_product[]=2", "page=1", "per_page=10", "select[]=current", "select[]=requested", "select[]=original"]
which is array of params from request
Then there is code that generates hash from array
arrays = strings.map do |segment|
k,v = segment.split("=")
[k, v && CGI.unescape(v)]
Hash[arrays]
CUrrent output -
"by_product[]": "2",
"page":"1",
"per_page":"10",
"select[]":"original"
Expected output -
"by_product[]":"1, 2",
"page":"1",
"per_page":"10",
"select[]":"current, requested, original"
The problem is - after split method there are few by_product[] and the last one just overrides any other params, so in result instead of hash with array as value of these params im getting only last one. And i'm not sure how to fix it. Any ideas? Or at least algorithms
So try this:
hash = {}
arrays = strings.map do |segment|
k,v = segment.split("=")
hash[k]||=[]
hash[k] << v
end
output is
1.9.3-p547 :025 > hash
=> {"by_product[]"=>["1", "2"], "page"=>["1"], "per_page"=>["10"], "select[]"=>["current", "requested", "original"]}
or if you want just strings do
arrays = strings.map do |segment|
k,v = segment.split("=")
hash[k].nil? ? hash[k] = v : hash[k] << ", " + v
end
Don't reinvent the wheel, CGI and Rack can already handle query strings.
Assuming your strings array comes from a single query string:
query = "by_product[]=1&by_product[]=2&page=1&per_page=10&select[]=current&select[]=requested&select[]=original"
you can use CGI::parse: (all values as arrays)
require 'cgi'
CGI.parse(query)
#=> {"by_product[]"=>["1", "2"], "page"=>["1"], "per_page"=>["10"], "select[]"=>["current", "requested", "original"]}
or Rack::Utils.parse_query: (arrays where needed)
require 'rack'
Rack::Utils.parse_nested_query(query)
# => {"by_product[]"=>["1", "2"], "page"=>"1", "per_page"=>"10", "select[]"=>["current", "requested", "original"]}
or Rack::Utils.parse_nested_query: (values without [] suffix)
require 'rack'
Rack::Utils.parse_nested_query(query)
# => {"by_product"=>["1", "2"], "page"=>"1", "per_page"=>"10", "select"=>["current", "requested", "original"]}
And if these are parameters for a Rails controller, you can just use params.
this will also work :
strings.inject({}){ |hash, string|
key, value = string.split('=');
hash[key] = (hash[key]|| []) << value;
hash;
}
output :
{"by_product[]"=>["1", "2"], "page"=>["1"], "per_page"=>["10"], "select[]"=>["current", "requested", "original"]}
As simple as that
array.map { |record| record*3 if condition }
record*3 is the resultant operation you wanna do to the array while mapping

Converting http_params to hash

I can obtain an array from the string
http_params="created_end_date=2013-02-28&created_start_date=2013-01-01&page_size=50&offset=0&order_id=0D1108211501118%0D%0A0D11108211501118%0D%0Ac%0D%0AD%0D%0ADK212071409743%0D%0AKK30109110100%0D%0AKK30111140300%0D%0AKK30111140400%0D%0AKK30115120100%0D%0AKK30115150100&page_number=1"
So I did myarray=http_params.split("&"):
myarray=["created_end_date=2013-02-28", "created_start_date=2013-01-01", "page_size=50", "offset=0", "order_id=0D1108211501118%0D%0A0D11108211501118%0D%0Ac%0D%0AD%0D%0ADK212071409743%0D%0AKK30109110100%0D%0AKK30111140300%0D%0AKK30111140400%0D%0AKK30115120100%0D%0AKK30115150100", "page_number=1"]
I need to convert this to a hash myhash, so that I can make a Rest Client post call for myhash.to_json. Basically it should be key,value pairs like:
{:created_end_date=>"2013-02-28",:created_start_date=>"2013-01-01"....}
I know that the inverse operation can be done like this:
http_params = myhash.map{|k,v| "#{k}=#{v}"}.join('&')
but I am unable to come up with neat code for this.
What's the best way I should go about this?
require 'cgi'
hash = CGI::parse http_params
Or you can use:
hash = Rack::Utils.parse_nested_query http_params
Which does not return the values as arrays.
With pure Ruby methods, you can convert your string into a Hash as follows:
"a=1&b=2".split('&').map { |h| Hash[*h.split("=")] }
=> [{"a"=>"1"}, {"b"=>"2"}]
A blog post how to operate on Ruby collections is here: http://thinkingonthinking.com/map-reduce-in-ruby/
To get symbols as keys, a small additional step is necessary:
"a=1&b=2".split('&').map { |h| hs = h.split("="); Hash[hs[0].to_sym, hs[1]] }
=> [{:a=>"1"}, {:b=>"2"}]
As last step, a merge of the inner Hash elements has to be done. This can be done like:
"a=1&b=2".split('&').map { |h| hs = h.split("="); Hash[hs[0].to_sym, hs[1]] }.inject({}) { |s, h| s.merge(h) }
=> {:a=>"1", :b=>"2"}

Hashes in hashes ruby on rails

I'm passing the below information through parameter from view to controller
parameters:{"Something"=>{"a" => "1", "b" => "0", "c" => "1", "d" => "0" #and so on}}
I want to access all the characters that have "1" as their value and concatenate into the string.
I tried
Something.each do |key, value|
if(value == "1")
string = string + key
end
end
It is throwing error saying that it could not execute nil.each and that i might be expecting an array.
It appears to me that Something is a hash and in turn has some hashes in it.
So i initialised Something to
Something = Hash.new { |Something, k| Something[k] = Hash.new }
But i still get the same error.
Just work with the params hash. This should do what you need:
params["Something"].select {|k, v| v == "1"}.keys.reduce(:+)
select filters the params to only those with the value "1"
keys returns an array with all the keys in the hash
reduce joins all elements with a concat operation (+)
Edit
To concatenate and add the "Extra" word:
For each parameter:
params["Something"].select {|k, v| v == "1"}.keys.inject("") {|result, p| result += "Extra #{p}"}
Only to the extra parameters, but not to the first one:
params["Something"].select {|k, v| v == "1"}.keys.inject {|result, p| result += "Extra #{p}"}
See more information on inject here.

Ruby on Rails 2 search string in Hash

I need help with this...
I have a hash like this:
#ingredients = Hash.new
#ingredients[1] = "Biscottes Mini(recondo)"
#ingredients[2] = "Abadejo"
#ingredients[3] = "Acelga"
#ingredients[4] = "Agua de Coco"
#ingredients[5] = "Ajo"
#ingredients[6] = "Almidón de Arroz"
#ingredients[7] = "Anillos Con Avena Integral cheerios (nestle)"
#ingredients[8] = "Apio"
I need to search into that hash in order to find "Biscottes Mini(recondo)" when I write "scotte"
Some help?
Thk!
Why do you use a Hash here and not an Array? You do not seem to use other keys than integers.
Anyway, this solution works for both Array and Hashes:
search_term = 'scotte'
# you could also use find_all instead of select
search_results = #ingredients.select { |key, val| val.include?(search_term) }
puts search_results.inspect
See http://ruby-doc.org/core/classes/Enumerable.html#M001488
You can call select (or find if you only want the first match) on a hash and then pass in a block that evaluates whether to include the key/value in the result hash. The block passes the key and value as arguments, so you can evaluate whether either the key or value matches.
search_value = "scotte"
#ingredients.select { |key, value| value.include? search_value }

Resources