Ruby convert Object to Hash
Solution 1
class Gift
def initialize
@name = "book"
@price = 15.95
end
end
gift = Gift.new
hash = {}
gift.instance_variables.each {|var| hash[var.to_s.delete("@")] = gift.instance_variable_get(var) }
p hash # => {"name"=>"book", "price"=>15.95}
Alternatively with each_with_object
:
gift = Gift.new
hash = gift.instance_variables.each_with_object({}) { |var, hash| hash[var.to_s.delete("@")] = gift.instance_variable_get(var) }
p hash # => {"name"=>"book", "price"=>15.95}
Solution 2
Just say (current object) .attributes
.attributes
returns a hash
of any object
. And it's much cleaner too.
Solution 3
Implement #to_hash
?
class Gift
def to_hash
hash = {}
instance_variables.each { |var| hash[var.to_s.delete('@')] = instance_variable_get(var) }
hash
end
end
h = Gift.new("Book", 19).to_hash
Solution 4
Gift.new.instance_values # => {"name"=>"book", "price"=>15.95}
Solution 5
You can use as_json
method. It'll convert your object into hash.
But, that hash will come as a value to the name of that object as a key. In your case,
{'gift' => {'name' => 'book', 'price' => 15.95 }}
If you need a hash that's stored in the object use as_json(root: false)
. I think by default root will be false. For more info refer official ruby guide
http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html#method-i-as_json
ma11hew28
Updated on December 11, 2021Comments
-
ma11hew28 over 2 years
Let's say I have a
Gift
object with@name = "book"
&@price = 15.95
. What's the best way to convert that to the Hash{name: "book", price: 15.95}
in Ruby, not Rails (although feel free to give the Rails answer too)? -
Jordan about 13 yearsYou can use inject to skip initializing the variable: gift.instance_variables.inject({}) { |hash,var| hash[var.to_s.delete("@")] = gift.instance_variable_get(var); hash }
-
ma11hew28 about 13 yearsNice. I replaced
var.to_s.delete("@")
withvar[1..-1].to_sym
to get symbols. -
Christopher Creutzig about 12 yearsThis is Rails, Ruby itself doesn't have
instance_values
. Note that Matt asked for a Ruby way, specifically not Rails. -
Erik Reedstrom about 12 yearsHe also said feel free to give the Rails answer as well... so I did.
-
bricker over 11 yearsNote that this is an ActiveModel-specific method, not a Ruby method.
-
Magne over 11 yearsfunny it's not part of the Rails framework. Seems like a useful thing to have there.
-
Griehle about 11 yearsThe attributes method returns a new hash with the values in - so no need to create another in the to_hash method. Like so: attribute_names.each_with_object({}) { |name, attrs| attrs[name] = read_attribute(name) } . See here: github.com/rails/rails/blob/master/activerecord/lib/…
-
Narfanator almost 11 yearsDon't use inject, use
gift.instance_variables.each_with_object({}) { |var,hash| hash[var.to_s.delete("@")] = gift.instance_variable_get(var) }
and get rid of the trailing; hash
-
dimitarvp about 10 yearsIn the case of Sequel -- use
.values
: sequel.jeremyevans.net/rdoc/classes/Sequel/Model/… -
Caleb about 9 yearsTechnically, it should be .to_hash, since # indicates class methods.
-
levinalex about 9 yearsActually, no. RDoc documentation says:
Use :: for describing class methods, # for describing instance methods, and use . for example code
(source: ruby-doc.org/documentation-guidelines.html) Also, official documentation (like the ruby CHANGELOG, github.com/ruby/ruby/blob/v2_1_0/NEWS) uses#
for instance methods and the dot for class methods pretty consistently. -
Nate Symer about 9 yearsI will never understand the ruby fetish for
each
.map
andinject
are much more powerful. This is one design qualm I have with Ruby:map
andinject
are implemented witheach
. It's simply bad computer science. -
Nate Symer about 8 yearsyou could have done this with map, your side-effect implementation is hurting my mind man!
-
YoTengoUnLCD over 7 yearsPlease use inject instead of this antipattern.
-
anothermh about 7 yearsOne-liner variant using
each_with_object
:instance_variables.each_with_object(Hash.new(0)) { |element, hash| hash["#{element}".delete("@").to_sym] = instance_variable_get(element) }
-
Sebastian Schürmann about 7 yearsGod to see both versions here ;) Liked it
-
bishal over 5 years
instance_values
can be used for all ruby objects for the similar output. -
Marvin about 5 yearsSlightly more concise:
hash = Hash[gift.instance_variables.map { |var| [var.to_s[1..-1], gift.instance_variable_get(var)] } ]
-
Aurelio about 3 yearsNot a ruby expert, but isn't this a much cleaner method than all others? It looks like the best answer to me, or am I missing something?
-
Teoman shipahi over 2 yearsVery helpful, thanks you!