Create multi-dimensional array or hash in ruby from JSON - ruby

I am using Rhomobile and trying to dynamically build a hash for the id and title of the buttons has of the Alert.show_popup, but am not quite getting it. What I want the end result to be, in effect, is:
Alert.show_popup( {
:message => 'Please Select Appropriate Address:',
:title => 'Get Nearby...',
:icon => :info,
:buttons => [
{'id' => '1', 'title' => 'Address 1'},
{'id' => '2', 'title' => 'Address 2'},
{'id' => '3', 'title' => 'Address 3'},
{'id' => '4', 'title' => 'Address 4'}
],
:callback => url_for(:action => :on_addressidentified_popup)
}
)
I've tried a few methods, but none have worked (build a string that looks like a hash and try_convert, etc.). Here was the latest one I tried which seemed close, but yet still far away:
nearbyaddresses = Rho::JSON.parse(#params['body'])
h = {}
nearbyaddresses.each do |location|
h[intIndex] = {}
h[intIndex][:id] = intIndex.to_s
h[intIndex][:title] = location["Address"].to_s
intIndex = intIndex + 1
end
Alert.show_popup( {
:message => 'Please Select Appropriate Address:',
:title => 'Get Nearby...',
:icon => :info,
:buttons => h,
:callback => url_for(:action => :on_addressidentified_popup)
}
)
Any ruby wizards here that can help me out?

How about
nearby_addresses_list = Rho::JSON.parse(#params['body'])
buttons_list = nearby_addresses_list.collect.each_with_index {|address, i|
{'id' => i, 'title' => address} #not sure if you need to dig into this at all.
}
This should leave buttons_list with this value
[{'id' => 0, 'title' => nearby_addresses_list[0]},
{'id' => 1, 'title' => nearby_addresses_list[1]}
{'id' => 2, 'title' => nearby_addresses_list[2]}
{'id' => 3, 'title' => nearby_addresses_list[3]}]
If you want the id's to start with 1, change the body of the collect statement to {'id' => i+1, 'title' => address}
Then just add buttons_list in as the value for the key :buttons.
Alert.show_popup( {
:message => 'Please Select Appropriate Address:',
:title => 'Get Nearby...',
:icon => :info,
:buttons => buttons_list,
:callback => url_for(:action => :on_addressidentified_popup)
})
If you're seeing weirdness between the desired output you mentioned first and the code you said was close, is it perhaps that you used symbols for the keys in your code (:id), and strings in your desired output ("id") ?

Here's how I addressed the issue. Works like a charm...
intIndex = 0
nearbyaddresses = Rho::JSON.parse(#params['body'])
##nearbyAddresses = nearbyaddresses
button_array = []
nearbyaddresses.each do |location|
opt = {'id' => intIndex.to_s, 'title' => location["Address"] }
button_array << opt
intIndex = intIndex + 1
end
Alert.show_popup( {
:message => 'Please Select Appropriate Address:',
:title => 'Get Nearby...',
:icon => :info,
:buttons => button_array,
:callback => url_for(:action => :getselectedaddress)
}
)

Related

Laravel 4 Database insert Error - preg_replace(): Parameter mismatch, pattern is a string while replacement is an array

In database seeder, I just want to insert some hard-coded data to the table.
$Pro1_id = DB::table('projects')->select('id')->where('projectName', '=', 'Project A')->get();
$data1_1 = array(
'id' => 1,
'projectID' => $Pro1_id,
'attributeID' => 1,
'levelID' => 2,
'percentage' => 20,
'risk_value' => 25186.86311,
'expectation_value' => 706455.9401,
);
$data1_2 = array(
'projectID' => $Pro1_id,
'attributeID' => 2,
'levelID' => 1,
'percentage' => 60,
'risk_value' => 530351.3397,
'expectation_value' => 392207.1248,
);
$data1 = [$data1_1, $data1_2];
DB::table('Mapping')->insert($data1);
However, I got the error:
[ErrorException] preg_replace(): Parameter mismatch, pattern is a
string while replacement is an array
It is so weird, because I did the same to another table, it worked.
DB::table('projects')->insert(array(
array(
'id' => Webpatser\Uuid\Uuid::generate(),
'projectName' => 'Project A',
'creator_id' => $pro1_creatorID,
'create_at' => \Carbon\Carbon::now()->toDateString(),
'lastEditor_id' => $pro1_creatorID,
'edit_at' => \Carbon\Carbon::now()->toDateString(),
'utility' => 1.597119661,
'exponential' => 4.94,
'projectValue' => 1225090.39
),
array(
'id' => Webpatser\Uuid\Uuid::generate(),
'projectName' => 'Project B',
'creator_id' => $pro2_creatorID,
'create_at' => \Carbon\Carbon::create(2014, 12, 12)->toDateString(),
'lastEditor_id' => $pro2_creatorID,
'edit_at' => \Carbon\Carbon::create(2014, 12, 12)->toDateString(),
'utility' => 1.754989409,
'exponential' => 5.78,
'projectValue' => 293760.36
),
array(
'id' => Webpatser\Uuid\Uuid::generate(),
'projectName' => 'Project C',
'creator_id' => $pro3_creatorID,
'create_at' => \Carbon\Carbon::create(2013, 10, 21)->toDateString(),
'lastEditor_id' => $pro3_creatorID,
'edit_at' => \Carbon\Carbon::create(2013, 10, 21)->toDateString(),
'utility' => 1.423114267,
'exponential' => 4.15,
'projectValue' => 1461924.67
)
)
);
I really don't understand why inserting into projects table works, but the one of the mapping table does NOT work.
They are exactly the same method.
I think your code is correct but when you insert the id in array, you are doing the wrong way.
$Pro1_id = DB::table('projects')->select('id')->where('projectName', '=', 'Project A')->get();
Here, $Pro1_id is Collection that contain value return from your query. Sometimes it might be one, but sometimes it might be 2 or 3.... So , your are doing the wrong way when you are inserting the id in the array. So , use foreach loop like this :
foreach($Pro1_id as $pro){
DB::table('Mapping')->insert(array(
'id' => 1,
'projectID' => $pro->id,
'attributeID' => 1,
'levelID' => 2,
'percentage' => 20,
'risk_value' => 25186.86311,
'expectation_value' => 706455.9401,
));
}
For simple , get returns Collection and is rather supposed to fetch multiple rows.
For more info . Check this

Magento AvS_fastsimpleimporter multiple addresses

Is it possible while creating new users with AvS_Fastsimpleimporter to add more than the standard address ?
Currently my array "data" looks like this
'email' => $kunde['email'],
'_website' => $_website,
'_store' => $_website . 'store',
'confirmation' => '',
'created_at' => $created_at,
'created_in' => 'Import',
'disable_auto_group_change' => 0,
'firstname' => $kunde['name_1'],
'group_id' => 3,
'kontonummer' => $kunde['kontonr'],
'kundennummer' => $kunde['kundennr'],
'lastname' => $lastname,
'password_hash' => $password_hash,
'store_id' => 0,
'website_id' => $country['id'],
'_address_city' => $kunde['ort'],
'_address_country_id' => $kunde['land'],
'_address_fax' => $kunde['fax'],
'_address_firstname' => $kunde['name_1'],
'_address_lastname' => $lastname,
'_address_postcode' => $kunde['plz'],
'_address_street' => $kunde['strasse'],
'_address_telephone' => $_address_telephone,
'_address_vat_id' => $kunde['ust_id'],
'_address_default_billing_' => 1,
'_address_default_shipping_' => 1,
And i want to add a second address with the AvS_Simpleimporter.
I tried to add a second array in data like this:
array_push($data, array(
'email' => null,
'_website' => null,
'_address_city' => checkRequiredInput($address['ort']),
'_address_country_id' => $address['land'],
'_address_firstname' => checkRequiredInputVadr($address['name_1']),
'_address_lastname' => checkRequiredInputVadr($address['name_2']),
'_address_postcode' => checkRequiredInput($address['plz']),
'_address_street' => checkRequiredInput($address['strasse']),
'_address_default_billing_' => 0,
'_address_default_shipping_' => 0,
));
And then executing with
$importer = Mage::getModel('fastsimpleimport/import');
$importer->setIgnoreDuplicates('password_hash')->processCustomerImport($data);
But this currently doesn't work. The second address is added as an extra array to data like this
.... data array
....
'_address_default_billing_' => 1
'_address_default_shipping_' => 1
[0] => 'email' => bla bla
'_website' => bla bla
and so son
Any help ?
Multiple addresses are imported as additional rows. Hence you need to:
'_address_country_id' => array($country1,$country2),
'_address_city' => array($city1, $city2),
....

Can't get value from nested pair in Omniauth hash.

I'll try to keep this simple, my previous wording was maybe a bit too verbose:
Here is the example Omniauth hash: https://github.com/mkdynamic/omniauth-facebook
I can access and save some values from this but not others. The field is writable, so I know its just my syntax (beginner, sorry!)
{
:provider => 'facebook',
:uid => '1234567',
:info => {
:nickname => 'jbloggs',
:email => 'joe#bloggs.com',
:name => 'Joe Bloggs',
:first_name => 'Joe',
:last_name => 'Bloggs',
:image => 'http://graph.facebook.com/1234567/picture?type=square',
:urls => { :Facebook => 'http://www.facebook.com/jbloggs' },
:location => 'Palo Alto, California',
:verified => true
},
:credentials => {
:token => 'ABCDEF...', # OAuth 2.0 access_token, which you may wish to store
:expires_at => 1321747205, # when the access token expires (it always will)
:expires => true # this will always be true
},
:extra => {
:raw_info => {
:id => '1234567',
:name => 'Joe Bloggs',
:first_name => 'Joe',
:last_name => 'Bloggs',
:link => 'http://www.facebook.com/jbloggs',
:username => 'jbloggs',
:location => { :id => '123456789', :name => 'Palo Alto, California' },
:gender => 'male',
:email => 'joe#bloggs.com',
:timezone => -8,
:locale => 'en_US',
:verified => true,
:updated_time => '2011-11-11T06:21:03+0000'
}
}
}
I can do this to get gender and save it.
location:auth.extra.raw_info["gender"]
Obviously though I dont want to save gender to location. I want to get "Palo Alto" and save it. But this doesn't work.
location.auth.extra.raw_info["location"]["name"]
What am I doing wrong? When I try it in console, I'm able to get the value.
try this
location.auth.extra.raw_info.location.name
or this
location.auth.extra.raw_info[:location][:name]
Yeah, what you suggested was what I was trying...and it turns out we were right but FB had changed how that hash was set up so it wasn't working. Lesson learned: subscribe FB's notifications next time :)

Ruby collection out of order

I have the following:
BB_AREAS = {
:about => {:link => "quem somos", :slug => "quem-somos"},
:expositors => {:link => "expositores",:slug => "expositores"},
:map => {:link => "planta", :slug => "planta"},
:activities => {:link => "atividades",:slug => "atividades"},
:address => {:link => "como chegar",:slug => "como-chegar"},
:support => {:link => "apoio", :slug => "apoio"},
:optin => {:link => "cadastro",:slug => "cadastro"},
:how_expositors => {:link => "como expor",:slug => "como-expor"},
:press => {:link => "imprensa",:slug => "imprensa"},
:contact => {:link => "contato",:slug => "contato"},
}
BB_MENU_AREAS = BB_AREAS.each_with_object({}) { |(k, v), h| h[k] = v[:link]}
BB_MENU_AREAS_SLUG = BB_AREAS.each_with_object({}) { |(k, v), h| h[k] = v[:slug]}
And in the view I have the following:
=render :partial => '/shared/menu', :collection => BB_MENU_AREAS.map {|link, menu| {:link => link, :menu => menu}}, :spacer_template => '/shared/menu_separator'
I want the menu to render in the same order of BB_AREAS, but it is rendered in an arbitrary order.
Hashes are ordered by insertion order in Ruby 1.9+, otherwise they have an internal order.
IMO this data belongs in an array of actual objects, though; roughly:
class Area
attr_accessor :name, :link, :slug
def initialize(name, link, slug)
#name = name
#link = link
#slug = slig
end
end
BB_AREAS = [
Area.new("About", "quem somos", "quem-somos"),
Area.new("Expositors", "expositores", "expositores"),
# etc.
]
If you actually need to extract individual components in order you may.
Ruby Hashs are orderless in Ruby 1.8 and lower. However, in Ruby 1.9 and higher, Hashes are ordered. There is a backward compatible solution though:
BB_AREAS = [
[:about , {:link => "quem somos", :slug => "quem-somos"}],
[:expositors , {:link => "expositores",:slug => "expositores"}],
[:map , {:link => "planta", :slug => "planta"}],
[:activities , {:link => "atividades",:slug => "atividades"}],
[:address , {:link => "como chegar",:slug => "como-chegar"}],
[:support , {:link => "apoio", :slug => "apoio"}],
[:optin , {:link => "cadastro",:slug => "cadastro"}],
[:how_expositors , {:link => "como expor",:slug => "como-expor"}],
[:press , {:link => "imprensa",:slug => "imprensa"}],
[:contact , {:link => "contato",:slug => "contato"}],
]
BB_MENU_AREAS = BB_AREAS.each_with_object({}) { |(k, v), h| h[k] = v[:link]}
BB_MENU_AREAS_SLUG = BB_AREAS.each_with_object({}) { |(k, v), h| h[k] = v[:slug]}
Nothing do change in your view. Additionally, in this data structure, instead of [key], you need to use .assoc(key)[1].

Getting key value in nested Hash by key array values

Sample hash:
{
"audio" => {
"audio/aac" => ["aac"],
"audio/mpeg" => ["mp3", "mp2"],
"audio/mp4" => ["m4a", "m4b", "m4r", "3gp"],
"audio/ogg" => ["ogg", "oga"],
"audio/flac" => ["flac"],
"audio/speex" => ["spx"],
"audio/x-ms-wma" => ["wma"],
"audio/x-pn-realaudio" => ["rm", "ram"],
"audio/vnd.wave" => ["wav"],
"audio/x-musepack" => ["mpc", "mp+", "mpp"],
"audio/x-aiff" => ["aiff", "aif", "aifc"],
"audio/x-tta" => ["tta"]
},
"video" => {
"video/mp4" => ["mp4"],
"video/mpeg" => ["mpg", "mpeg"],
"video/x-m4v" => ["m4v"],
"video/quicktime" => ["mov"],
"video/x-msvideo" => ["avi"],
"video/x-flv" => ["flv"],
"video/webm" => ["webm"]
}
}
What's the best way given a file extension to get the associated content type (first match is okay)?
Searching for "flac" should return "audio/flac".
Currently I'm using this:
hsh.each_key do |group|
hsh[group].each do |k,v|
return k if v.include?(extension)
end
end
Unraveling that sort of structure is best done when it's created. But, you can loop through the various levels and get something useful from it. If I assign your initial hash to mime_hash I can unravel it using:
Hash[*mime_hash.map{ |av, types| types.map{ |mime_type, extensions| extensions.product([mime_type]) } }.flatten]
or more verbosely:
Hash[
*mime_hash.map{ |av, types|
types.map{ |mime_type, extensions|
extensions.product([mime_type])
}
}.flatten
]
Which will return:
{
"aac" => "audio/aac",
"mp3" => "audio/mpeg",
"mp2" => "audio/mpeg",
"m4a" => "audio/mp4",
"m4b" => "audio/mp4",
"m4r" => "audio/mp4",
"3gp" => "audio/mp4",
"ogg" => "audio/ogg",
"oga" => "audio/ogg",
"flac" => "audio/flac",
"spx" => "audio/speex",
"wma" => "audio/x-ms-wma",
"rm" => "audio/x-pn-realaudio",
"ram" => "audio/x-pn-realaudio",
"wav" => "audio/vnd.wave",
"mpc" => "audio/x-musepack",
"mp+" => "audio/x-musepack",
"mpp" => "audio/x-musepack",
"aiff" => "audio/x-aiff",
"aif" => "audio/x-aiff",
"aifc" => "audio/x-aiff",
"tta" => "audio/x-tta",
"mp4" => "video/mp4",
"mpg" => "video/mpeg",
"mpeg" => "video/mpeg",
"m4v" => "video/x-m4v",
"mov" => "video/quicktime",
"avi" => "video/x-msvideo",
"flv" => "video/x-flv",
"webm" => "video/webm"
}
As you've already realized the data structure you have is horrible to search in the fashion you want. Assuming you're going to be searching the same data over and over what you should do is create an index for it.
There are many ways of doing this but the simplest is probably just to flatten the hash and invert it so that your keys become values and vice-versa. That way you can simply search it by calling content_types['flac']
A section of the example hash might end up like this:
{
"aac" => "audio/aac",
"mp3" => "audio/mpeg",
"mp2" => "audio/mpeg",
"m4a" => "audio/mp4",
"m4b" => "audio/mp4",
"m4r" => "audio/mp4",
"3gp" => "audio/mp4",
"flac" => "audio/flac"
}
Try using rassoc()
Definition:
Searches through the hash comparing obj with the value using ==. Returns the first key-value pair (two-element array) that matches. See also Array#rassoc.
a = {1=> "one", 2 => "two", 3 => "three", "ii" => "two"}
a.rassoc("two") #=> [2, "two"]
a.rassoc("four") #=> nil

Resources