I have a hash of strings
navigable_objects = { 'Dashboard' => root_path,
'Timesheets' => timesheets_path,
'Clients' => clients_path,
'Projects' => projects_path,
}
I want to convert them into another hash where the key is again the key, but the value is either the string 'active' or empty string depending on whether the current controller name contains the key.
For example, lets say that the current controller name is "ClientsController". The result I should get is:
{ 'Dashboard' => '',
'Timesheets' => '',
'Clients' => 'active',
'Projects' => ''
}
Here is how I am currently doing it:
active = {}
navigable_objects.each do |name, path|
active[name] = (controller.controller_name.include?(name)) ? 'active' : '')
end
I feel that while this works, there is a better way to do this in Ruby, possibly using inject
or each_with_objects
?
We can merge two hashes using the merge() method. When using the merge() method: Each new entry is added to the end. Each duplicate-key entry's value overwrites the previous value.
Merge two hashes On of the ways is merging the two hashes. In the new hash we will have all the key-value pairs of both of the original hashes. If the same key appears in both hashes, then the latter will overwrite the former, meaning that the value of the former will disappear. (See the key "Foo" in our example.)
You might get your key and value from user input, so you can use Ruby . to_sym can convert a string to a symbol, and . to_i will convert a string to an integer.
In Ruby you can create a Hash by assigning a key to a value with => , separate these key/value pairs with commas, and enclose the whole thing with curly braces.
UPDATE: I posted another answer that I think is better for your situation. I'm leaving this one un-edited though because it has merit on its own for similar problems.
Here's the way I'd do it:
Hash[*navigable_objects.map{ |k,v| [k, controller.controller_name.include?(k) ? 'active' : ''] }.flatten]
You can run map
on a hash that gets key and value pairs as input to the block. Then you can construct pairs of key/values into arrays as the output. Finally, Running Hash[*key_value_pairs.flatten]
is a nice trick to turn it back into a hash. This works because you can pass an array of arguments to the Hash[]
constructor to generate a hash (Hash[1, 2, 3, 4]
=> { 1 => 2, 3 => 4 }
). And flatten
turns the key value pairs into an array, and *
operator turns an array into a list of arguments.
Here's a verbose version in case you want to see more clearly what's going on:
key_value_pairs = navigable_objects.map do |key, value|
new_value = controller.controller_name.include?(k) ? 'active' : ''
[key, new_value]
end
new_hash = Hash[*key_value_pairs.flatten]
Update: This above is compatible with ruby 1.8. As Andrew pointed out in the comments:
In 1.9 you don't need the * or flatten as Hash[] takes key-value array pairs
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With