Converting nested hash keys from CamelCase to snake_case in Ruby
You need to treat Array and Hash separately. And, if you're in Rails, you can use underscore
instead of your homebrew to_snake_case
. First a little helper to reduce the noise:
def underscore_key(k)
k.to_s.underscore.to_sym
# Or, if you're not in Rails:
# to_snake_case(k.to_s).to_sym
end
If your Hashes will have keys that aren't Symbols or Strings then you can modify underscore_key
appropriately.
If you have an Array, then you just want to recursively apply convert_hash_keys
to each element of the Array; if you have a Hash, you want to fix the keys with underscore_key
and apply convert_hash_keys
to each of the values; if you have something else then you want to pass it through untouched:
def convert_hash_keys(value)
case value
when Array
value.map { |v| convert_hash_keys(v) }
# or `value.map(&method(:convert_hash_keys))`
when Hash
Hash[value.map { |k, v| [underscore_key(k), convert_hash_keys(v)] }]
else
value
end
end
Convert hash keys to lowercase -- Ruby Beginner
You can use something like this:
CSV.foreach(file, :headers => true) do |row|
new_hash = {}
row.to_hash.each_pair do |k,v|
new_hash.merge!({k.downcase => v})
end
Users.create!(new_hash)
end
I had no time to test it but, you can take idea of it.
Hope it will help
Automatically convert hash keys to camelCase in JBuilder
As Bryce has mentioned, Jbuilder uses to_json instead of processing the hash.
A simple solution is to use json.set!
to manually serialize the hash.
json.key_format! camelize: :lower
json.data_object do
@foo.each do |key, value|
json.set! key, value
end
end
Although, there is an issue: if @foo is empty, it won't create an object at all. These are the solutions I found:
Define an empty hash before the serialization
json.key_format! camelize: :lower
json.data_object({}) # don't forget parentheses or Ruby will handle {} as a block
json.data_object do
@foo.each do |key, value|
json.set! key, value
end
endSerialize an empty hash if the source variable is empty
json.key_format! camelize: :lower
if (@foo.empty?) do
json.data_object({})
else
json.data_object do
@foo.each do |key, value|
json.set! key, value
end
end
endOr if you prefer your code flat
json.key_format! camelize: :lower
json.data_object({}) if @foo.empty?
json.data_object do
@foo.each do |key, value|
json.set! key, value
end
end unless @foo.empty?
However, those solutions will not work if you have to serialize nested objects. You can achieve deep serialization by monkeypatching the json
object inside Jbuilder
def json.hash!(name, hash)
if hash.empty?
set! name, {}
else
set! name do
hash.each do |key, value|
if value.is_a?(Hash)
hash! key, value
else
set! key, value
end
end
end
end
end
Then you can simply use json.hash! :data_object, @foo
and get the desired result.
Rails - Serialize Model to JSON with camelize
It seems weird to me to use camelized attribute names in Rails, let alone json. I would stick to the conventions and use underscored variable names.
However, have a look at this gem: RABL. It should be able to help you out.
How do I convert a Ruby hash so that all of its keys are symbols?
hash = {"apple" => "banana", "coconut" => "domino"}
Hash[hash.map{ |k, v| [k.to_sym, v] }]
#=> {:apple=>"banana", :coconut=>"domino"}
@mu is too short: Didn't see word "recursive", but if you insist (along with protection against non-existent to_sym
, just want to remind that in Ruby 1.8 1.to_sym == nil
, so playing with some key types can be misleading):
hash = {"a" => {"b" => "c"}, "d" => "e", Object.new => "g"}
s2s =
lambda do |h|
Hash === h ?
Hash[
h.map do |k, v|
[k.respond_to?(:to_sym) ? k.to_sym : k, s2s[v]]
end
] : h
end
s2s[hash] #=> {:d=>"e", #<Object:0x100396ee8>=>"g", :a=>{:b=>"c"}}
Converting camel case to underscore case in ruby
Rails' ActiveSupport
adds underscore to the String using the following:
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
Then you can do fun stuff:
"CamelCase".underscore
=> "camel_case"
Iterate over a deeply nested level of hashes in Ruby
If I understand the goal, then you should be able to pass in the parent to your save method. For the top level, it will be nil. The following shows the idea where puts
is used as a place holder for the "save".
def save_pair(parent, myHash)
myHash.each {|key, value|
value.is_a?(Hash) ? save_pair(key, value) :
puts("parent=#{parent.nil? ? 'none':parent}, (#{key}, #{value})")
}
end
Here is an example call to it:
hash = Hash.new
hash["key1"] = "value1"
hash["key2"] = "value2"
hash["key3"] = Hash.new
hash["key3"]["key4"] = "value4"
hash["key3"]["key5"] = "value5"
hash["key6"] = Hash.new
hash["key6"]["key7"] = "value7"
hash["key6"]["key8"] = Hash.new
hash["key6"]["key8"]["key9"] = "value9"
save_pair(nil, hash)
How to elegantly rename all keys in a hash in Ruby?
ages = { 'Bruce' => 32, 'Clark' => 28 }
mappings = { 'Bruce' => 'Bruce Wayne', 'Clark' => 'Clark Kent' }
ages.transform_keys(&mappings.method(:[]))
#=> { 'Bruce Wayne' => 32, 'Clark Kent' => 28 }
Parse JSON in Rails app that is camelCase
I found some code here so I post it again for you so it is easy to copy.
def underscore_key(k)
if defined? Rails
k.to_s.underscore.to_sym
else
to_snake_case(k.to_s).to_sym
end
end
def to_snake_case(string)
string.gsub(/::/, '/').
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
gsub(/([a-z\d])([A-Z])/,'\1_\2').
tr("-", "_").
downcase
end
def convert_hash_keys(value)
case value
when Array
value.map { |v| convert_hash_keys(v) }
# or `value.map(&method(:convert_hash_keys))`
when Hash
Hash[value.map { |k, v| [underscore_key(k), convert_hash_keys(v)] }]
else
value
end
end
here are some small tests to prove the functionality:
p convert_hash_keys({abc:"x"}) # => {:abc=>"x"}
p convert_hash_keys({abcDef:"x"}) # => {:abc_def=>"x"}
p convert_hash_keys({AbcDef:"x"}) # => {:abc_def=>"x"}
p convert_hash_keys(["abc"]) # => ["abc"]
p convert_hash_keys([abc:"x"]) # => [{:abc=>"x"}]
p convert_hash_keys([abcDef:"x"]) # => [{:abc_def=>"x"}]
I hope that meets your requirements.
Related Topics
How to Turn a Ruby Method into a Block
Use Global or Constant Variable in Ruby/Rails
Rake Db:Migrate Error with MySQL2 Gem - Library Not Loaded: Libssl.1.0.0.Dylib
How to Look Up Elevation Data by Lat/Lng
Capistrano 3 Execute Within a Directory
Dynamically Creating Class in Ruby
Ruby: "&& Return" VS "And Return"
How to Create Md5 Hash with Hmac Module in Ruby
Ruby $Stdin.Gets Without Showing Chars on Screen
Best Way to Group by Date with Mongoid
Ruby: How to Generate CSV Files That Has Excel-Friendly Encoding
How to Use Ajax Send Data to Controller in Ruby on Rails
Set the Display Precision of a Float in Ruby
Can't Enter Umlauts in Ruby 1.9.3 Irb
Webkit_Server Hangs Periodically When Run from Capybara in Ruby
Gem::Ext::Builderror: Error: Failed to Build Gem Native Extension Bcrypt-Ruby