Append a hash to a GET endpoint's query params in Rails - ruby-on-rails

I'm integrating with a 3rd party service for which the complete URL string of a GET request needs to look something like:
<URL>/some_endpoint?JsonData={"key1" => "value1", "key2" => "value2", "key3" => "value3"}
To be clear, this request has only one param, JsonData and the entire hash is the corresponding value. All values inside the hash are URL-safe.
JSON/CGI/URI encodings don't seem to help here.
How do I not encode/add escape characters here?

Perhaps you're looking for the to_query method?
2.3.1 :024 > {"key1" => "value1", "key2" => "value2", "key3" => "value3"}.to_query
=> "key1=value1&key2=value2&key3=value3"
Or:
2.3.1 :029 > {"JsonData" => {"key1" => "value1", "key2" => "value2", "key3" => "value3"}}.to_query
=> "JsonData%5Bkey1%5D=value1&JsonData%5Bkey2%5D=value2&JsonData%5Bkey3%5D=value3"
Or, as stated in the docs,
An optional namespace can be passed to enclose key names:
2.3.1 :030 > {"key1" => "value1", "key2" => "value2", "key3" => "value3"}.to_query('JsonData')
=> "JsonData%5Bkey1%5D=value1&JsonData%5Bkey2%5D=value2&JsonData%5Bkey3%5D=value3"
So, it could look something like
2.3.1 :031 > "<URL>/some_endpoint?#{{"key1" => "value1", "key2" => "value2", "key3" => "value3"}.to_query('JsonData')}"
=> "<URL>/some_endpoint?JsonData%5Bkey1%5D=value1&JsonData%5Bkey2%5D=value2&JsonData%5Bkey3%5D=value3"

How about manually creating the string, like this:
hash = {"key1" => "value1", "key2" => "value2", "key3" => "value3"}
url = "/some_endpoint?JsonData={" + hash.map { |k, v| "'#{k}' => '#{v}'" }.join(", ") + "}"
#=> "/some_endpoint?JsonData={'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3'}"

This is quite embarassing. Converting the hash to JSON did work eventually.
The final URL looks like:
hash = {"key1" => "value1", "key2" => "value2", "key3" => "value3"}
"#{URL}/some_endpoint?JsonData=#{hash.to_json}"

Related

Parsing XML HTTParty response

I was getting data from an api using HTTParty. I managed to get back the XML response, and it looks like HTTParty has made that xml response into Ruby.
How can I navigate through the hashes and get the data I need? For instance, say I wanted the "Name", which is "29TH AVENUE STN/ARBUTUS".
The API key works fine, since I am getting a response back.
Just not too sure how I can navigate through and get the data I want, and to put it into my view.
index.html.erb:
<% #courses.each do |course| %>
<%= course %>
<% end %>
HTTparty response:
["Route", {
"RouteNo" => "016", "Name" => "29TH AVENUE STN/ARBUTUS ", "OperatingCompany" => "CMBC", "Patterns" => {
"Pattern" => [{
"PatternNo" => "E5TP", "Destination" => "29TH AVE STN", "RouteMap" => {
"Href" => "http://nb.translink.ca/geodata/trip/016-E5TP.kmz"
}, "Direction" => "EAST"
}, {
"PatternNo" => "EB1", "Destination" => "29TH AVE STN", "RouteMap" => {
"Href" => "http://nb.translink.ca/geodata/trip/016-EB1.kmz"
}, "Direction" => "EAST"
}, {
"PatternNo" => "EB5", "Destination" => "29TH AVE STN", "RouteMap" => {
"Href" => "http://nb.translink.ca/geodata/trip/016-EB5.kmz"
}, "Direction" => "EAST"
}]
}
}]
Model for getting the response
class Checker
include HTTParty
base_uri 'http://api.translink.ca/rttiapi/v1/routes'
default_params apikey: "[my proper api key]"
format :xml
def self.for term
get("", query: {stopNo: term})["Routes"]["Route"]["RouteNo"]
end
end
Controller for the Model
class TimesController < ApplicationController
def index
#search_term = '51048'
#courses = Checker.for(#search_term)
end
end
Assuming you have a response shown:
resp = ["Route", {
"RouteNo" => "016", "Name" => "29TH AVENUE STN/ARBUTUS ", "OperatingCompany" => "CMBC", "Patterns" => {
"Pattern" => [{
"PatternNo" => "E5TP", "Destination" => "29TH AVE STN", "RouteMap" => {
"Href" => "http://nb.translink.ca/geodata/trip/016-E5TP.kmz"
}, "Direction" => "EAST"
}, {
"PatternNo" => "EB1", "Destination" => "29TH AVE STN", "RouteMap" => {
"Href" => "http://nb.translink.ca/geodata/trip/016-EB1.kmz"
}, "Direction" => "EAST"
}, {
"PatternNo" => "EB5", "Destination" => "29TH AVE STN", "RouteMap" => {
"Href" => "http://nb.translink.ca/geodata/trip/016-EB5.kmz"
}, "Direction" => "EAST"
}]
}
}]
which is in turn an array of two elements, first being 'Route' and the last being a hash with all properties, to get the name use simply:
resp.last['Name']

Ruby sort by hash and value

I have data like this:
hash_data = [
{:key1 => 'value4', :sortby => 4},
{:key1 => 'valuesds6', :sortby => 6},
{:key1 => 'valuedsd', :sortby => 1},
{:key1 => 'value2_data_is_here', :sortby => 2}
]
I want to sort it to this by the key sortby
hash_data = [
{:key1 => 'valuedsd', :sortby => 1},
{:key1 => 'value2_data_is_here', :sortby => 2},
{:key1 => 'value4', :sortby => 4},
{:key1 => 'valuesds6', :sortby => 6}
]
I have tried using bubble sort, but is there any inbuilt function in a Hash class for such purposes?
Enumerable#sort_by to the rescue:
hash_data.sort_by { |hash| hash[:sortby] }
#=> [{:key1=>"valuedsd", :sortby=>1}, {:key1=>"value2_data_is_here", :sortby=>2}, {:key1=>"value4", :sortby=>4}, {:key1=>"valuesds6", :sortby=>6}]
If you don't care about initial object, I would suggest using Array#sort_by! to modify inplace - it is more resource-efficient:
hash_data.sort_by! { |hash| hash[:sortby] }
If you have different types of data as values to sortby key, you should first unify the data type and only then perform sorting.
To have array sorted in descending order, use Enumerable#reverse (or reverse!):
hash_data.sort_by {|hash| hash[:sortby] }.reverse
#=> [{:key1=>"valuesds6", :sortby=>6}, {:key1=>"value4", :sortby=>4}, {:key1=>"value2_data_is_here", :sortby=>2}, {:key1=>"valuedsd", :sortby=>1}]
Another option for sorting in descending order is the following - note minus sign (credits to #sagarpandya82):
hash_data.sort_by {|hash| -hash[:sortby] }

How to permit nested hash parameters with the StrongParameters gem?

I am using Ruby on Rails 4.1 and I would like to permit the following incoming parameters by using the StrongParameters gem:
# Parameters:
{
"my_key" => {
"one" => {
"0" => { "a" => "a_value", "b" => "b_value"},
"1" => { "a" => "a_value", "b" => "b_value"},
"2" => { "a" => "a_value", "b" => "b_value"}
},
"two" => {
"0" => { "c" => "c_value", "d" => "d_value"},
"1" => { "c" => "c_value", "d" => "d_value"},
"2" => { "c" => "c_value", "d" => "d_value"}
}
}
}
In controller I tried
params
.require(:my_key)
.permit(
[
:one => [
"0" => [:a, :b],
"1" => [:a, :b],
"2" => [:a, :b]
],
:two => [
"0" => [:c, :d],
"1" => [:c, :d],
"2" => [:c, :d]
]
]
)
and
params
.require(:my_key)
.permit(
{
:one => {
"0" => [:a, :b],
"1" => [:a, :b],
"2" => [:a, :b]
},
:two => {
"0" => [:c, :d],
"1" => [:c, :d],
"2" => [:c, :d]
}
}
)
But I get the error
ActionController::UnpermittedParameters (found unpermitted parameters: a, b)
How above parameters should be permitted?
Here is what you need to do:
Remove Strong Parameters gem from your Gemfile.
Use this in the controller.
params.require(:my_key).permit({:one=>[:a, :b],:two=>[:c, :d]})
I think this has something to do with how nested attributes work. The ids "0", "1", "2" etc are implicit.
You can test in the console like this:
$ bin/rails c
Loading development environment (Rails 4.1.2)
2.1.0 :001 > params = ActionController::Parameters.new "my_key"=>{"one"=>{"0"=>{"a"=>"a_value","b"=>"b_value"},"1"=>{"a"=>"a_value","b"=>"b_value"},"2"=>{"a"=>"a_value","b"=>"b_value"}},"two"=>{"0"=>{"c"=>"c_value","d"=>"d_value"},"1"=>{"c"=>"c_value","d"=>"d_value"},"2"=>{"c"=>"c_value","d"=>"d_value"}}}
=> {"my_key"=>{"one"=>{"0"=>{"a"=>"a_value", "b"=>"b_value"}, "1"=>{"a"=>"a_value", "b"=>"b_value"}, "2"=>{"a"=>"a_value", "b"=>"b_value"}}, "two"=>{"0"=>{"c"=>"c_value", "d"=>"d_value"}, "1"=>{"c"=>"c_value", "d"=>"d_value"}, "2"=>{"c"=>"c_value", "d"=>"d_value"}}}}
2.1.0 :002 > p = params.require(:my_key).permit({:one=>[:a, :b],:two=>[:c, :d]})
=> {"one"=>{"0"=>{"a"=>"a_value", "b"=>"b_value"}, "1"=>{"a"=>"a_value", "b"=>"b_value"}, "2"=>{"a"=>"a_value", "b"=>"b_value"}}, "two"=>{"0"=>{"c"=>"c_value", "d"=>"d_value"}, "1"=>{"c"=>"c_value", "d"=>"d_value"}, "2"=>{"c"=>"c_value", "d"=>"d_value"}}}
2.1.0 :003 >

What is an elegant way of modifying hashes inside an array within a nested hash in Ruby

I would like to transform this
def some_process(k,v)
return "#{v}_#{k}"
end
a_hash = {
"i_love_hashes" => {
"thing" => 20,
"other_thing" => "0",
"yet_another_thing" => "i disagree",
"_peculiar_thing" => [
{"count" => 30,
"name" => "freddie"},
{"count" => 15,
"name" => "johhno"},
{"count" => 12,
"name" => "mohammed"},
]
},
"as_do_i" => {
"thing" => 10,
"other_thing" => "2",
"yet_another_thing" => "i strongly agree",
"_peculiar_thing" => [
{"count" => 10,
"name" => "frodo"},
{"count" => 4,
"name" => "bilbo"},
{"count" => 2,
"name" => "elizabeth"},
]
}
}
into this
{
"i_love_hashes"=>{
"thing"=>20,
"other_thing"=>"0",
"yet_another_thing"=>"i disagree",
"_peculiar_thing"=> [
{"count"=>30, "name"=>"freddie", :sinister_name=>"freddie_i_love_hashes"},
{"count"=>15, "name"=>"johhno", :sinister_name=>"johhno_i_love_hashes"},
{"count"=>12, "name"=>"mohammed", :sinister_name=>"mohammed_i_love_hashes"}
]},
"as_do_i"=>{
"thing"=>10,
"other_thing"=>"2",
"yet_another_thing"=>"i strongly agree",
"_peculiar_thing"=>[
{"count"=>10, "name"=>"frodo", :sinister_name=>"frodo_as_do_i"},
{"count"=>4, "name"=>"bilbo", :sinister_name=>"bilbo_as_do_i"},
{"count"=>2, "name"=>"elizabeth", :sinister_name=>"elizabeth_as_do_i"}
]
}
}
this is the code I am currently using to achieve this
a_hash.each_with_object({}) do |(k,v),o|
o.merge!({k =>
v.each_with_object({}) do |(a,b),g|
g.merge!({ a =>
(b.is_a?(Array) ? b.collect {|x| x.merge({sinister_name: (some_process k, x["name"])})} : b)
})
end
})
end
Ignoring the specific details of what is being returned by "some_process" (what is important is that it depends on the outer most key and the inner name values, in this example), are there any alternatives that would be considered more elegant?
Why not do a recursive function?
def add_siniter(hash)
hash[:siniter_name] = "#{hash['name']}_i_love_hashes"
hash
end
def format_hash(item)
case item
when Hash then item.keys.each{|key| format_hash(item[key])}
when Array then item.map!{|h| add_siniter(h)}
end
end
format_hash(a_hash)

Ruby Hash creation

I am a newbie in Ruby and I am trying to learn Ruby these day. I was going through Hash today and got stuck in problem related to Hash
I have the following Hash
{"key1" => ["param_1","param_2"], "key2" => ["param_3","param_4"], "key3" => "param_5", "key4" => "param_6","key5" => ["param_7","param_8"]}
and I want to convert the above Hash into the following.
{"my_hash" => [ {"name" => "key1","value" => ["param_1","param_2"]},
{"name" => "key2","value" => ["param_3","param_4"]},
{"name" => "key3","value" => ["param_5"]},
{"name" => "key4","value" => ["param_6"]},
{"name" => "key5","value" => ["param_7","param_8"]}
]
}
Can someone show me how can i do it in Ruby in a efficient way.
hsh = {"key1" => ["param_1","param_2"],
"key2" => ["param_3","param_4"], "key3" => "param_5",
"key4" => "param_6","key5" => ["param_7","param_8"]}
hsh.map{|k,v| {name: k,value: Array(v) }}
# => [{:name=>"key1", :value=>["param_1", "param_2"]},
# {:name=>"key2", :value=>["param_3", "param_4"]},
# {:name=>"key3", :value=>["param_5"]},
# {:name=>"key4", :value=>["param_6"]},
# {:name=>"key5", :value=>["param_7", "param_8"]}]
hsh = {"key1" => ["param_1","param_2"],
"key2" => ["param_3","param_4"], "key3" => "param_5",
"key4" => "param_6","key5" => ["param_7","param_8"]}
hsh.map{|k,v| {"name" => k,"value" => Array(v) }}
# => [{"name"=>"key1", "value"=>["param_1", "param_2"]},
# {"name"=>"key2", "value"=>["param_3", "param_4"]},
# {"name"=>"key3", "value"=>["param_5"]},
# {"name"=>"key4", "value"=>["param_6"]},
# {"name"=>"key5", "value"=>["param_7", "param_8"]}]

Resources