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)?
-
20Would @gift.attributes.to_options do? – Mr. L Feb 17 '11 at 15:02
-
11) Is gift a ActiveRecord object? 2)can we assume @name/@price are not just instance variables but also reader accessors? 3) you want only name and price or all the attributes in a gift whatever they are? – tokland Feb 17 '11 at 16:25
-
@tokland, 1) no, `Gift` is [exactly like @nash has defined](http://stackoverflow.com/questions/5030553/ruby-convert-object-to-hash/5030763#5030763), except, 2) sure, the instance variables can have reader accessors. 3) All the attributes in gift. – ma11hew28 Feb 17 '11 at 17:17
-
Ok. The question about instance variables/readers access was to know if wanted an outside access (nash) or inside method (levinalex). I updated my answer for the "inside" approach. – tokland Feb 17 '11 at 17:38
20 Answers
Just say (current object) .attributes
.attributes
returns a hash
of any object
. And it's much cleaner too.

- 44,205
- 11
- 83
- 107

- 3,425
- 2
- 14
- 5
-
159
-
6In the case of Sequel -- use `.values`: http://sequel.jeremyevans.net/rdoc/classes/Sequel/Model/InstanceMethods.html – dimitarvp Apr 16 '14 at 13:43
-
3`instance_values` can be used for all ruby objects for the similar output. – bishal Jan 22 '19 at 11:37
-
Not 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? – Aurelio May 19 '21 at 09:49
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}

- 57,827
- 19
- 139
- 159

- 24,459
- 5
- 79
- 77
-
3You 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 } – Jordan Feb 17 '11 at 21:05
-
8Nice. I replaced `var.to_s.delete("@")` with `var[1..-1].to_sym` to get symbols. – ma11hew28 Feb 21 '11 at 18:38
-
3Don'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` – Narfanator Jun 10 '13 at 00:14
-
2I will never understand the ruby fetish for `each`. `map` and `inject` are much more powerful. This is one design qualm I have with Ruby: `map` and `inject` are implemented with `each`. It's simply bad computer science. – Nate Symer Apr 21 '15 at 17:01
-
Slightly more concise: `hash = Hash[gift.instance_variables.map { |var| [var.to_s[1..-1], gift.instance_variable_get(var)] } ]` – Marvin Apr 13 '19 at 21:04
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

- 24,223
- 14
- 73
- 76

- 5,889
- 2
- 34
- 48
-
-
7Actually, no. RDoc documentation says: `Use :: for describing class methods, # for describing instance methods, and use . for example code` (source: http://ruby-doc.org/documentation-guidelines.html) Also, official documentation (like the ruby CHANGELOG, https://github.com/ruby/ruby/blob/v2_1_0/NEWS) uses `#` for instance methods and the dot for class methods pretty consistently. – levinalex Apr 14 '15 at 16:25
-
-
One-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) }` – anothermh Mar 28 '17 at 20:14
Gift.new.instance_values # => {"name"=>"book", "price"=>15.95}

- 627
- 5
- 3
-
11This is Rails, Ruby itself doesn't have `instance_values`. Note that Matt asked for a Ruby way, specifically not Rails. – Christopher Creutzig Mar 28 '12 at 19:56
-
30He also said feel free to give the Rails answer as well... so I did. – Erik Reedstrom May 03 '12 at 16:33
-
-
I'd preface your answer with something like "Rails provides the #instance_values method" – Brett H Jul 08 '22 at 17:53
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

- 2,973
- 1
- 20
- 20
For Active Record Objects
module ActiveRecordExtension
def to_hash
hash = {}; self.attributes.each { |k,v| hash[k] = v }
return hash
end
end
class Gift < ActiveRecord::Base
include ActiveRecordExtension
....
end
class Purchase < ActiveRecord::Base
include ActiveRecordExtension
....
end
and then just call
gift.to_hash()
purch.to_hash()

- 627
- 6
- 11
-
2funny it's not part of the Rails framework. Seems like a useful thing to have there. – Magne Dec 14 '12 at 21:31
-
The 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: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_methods.rb – Chris Kimpton Mar 02 '13 at 11:14
-
you could have done this with map, your side-effect implementation is hurting my mind man! – Nate Symer Mar 23 '16 at 19:59
class Gift
def to_hash
instance_variables.map do |var|
[var[1..-1].to_sym, instance_variable_get(var)]
end.to_h
end
end

- 66,169
- 13
- 144
- 170
If you are not in an Rails environment (ie. don't have ActiveRecord available), this may be helpful:
JSON.parse( object.to_json )

- 5,674
- 2
- 30
- 30
You can write a very elegant solution using a functional style.
class Object
def hashify
Hash[instance_variables.map { |v| [v.to_s[1..-1].to_sym, instance_variable_get v] }]
end
end

- 2,185
- 1
- 20
- 27
Recursively convert your objects to hash using 'hashable' gem (https://rubygems.org/gems/hashable) Example
class A
include Hashable
attr_accessor :blist
def initialize
@blist = [ B.new(1), { 'b' => B.new(2) } ]
end
end
class B
include Hashable
attr_accessor :id
def initialize(id); @id = id; end
end
a = A.new
a.to_dh # or a.to_deep_hash
# {:blist=>[{:id=>1}, {"b"=>{:id=>2}}]}

- 2,171
- 21
- 17
You should override the inspect
method of your object to return the desired hash, or just implement a similar method without overriding the default object behaviour.
If you want to get fancier, you can iterate over an object's instance variables with object.instance_variables

- 3,304
- 19
- 22
You can use symbolize_keys
and in-case you have nested attributes we can use deep_symbolize_keys
:
gift.as_json.symbolize_keys => {name: "book", price: 15.95}

- 330
- 1
- 9
Produces a shallow copy as a hash object of just the model attributes
my_hash_gift = gift.attributes.dup
Check the type of the resulting object
my_hash_gift.class
=> Hash

- 61
- 1
- 1
If you need nested objects to be converted as well.
# @fn to_hash obj {{{
# @brief Convert object to hash
#
# @return [Hash] Hash representing converted object
#
def to_hash obj
Hash[obj.instance_variables.map { |key|
variable = obj.instance_variable_get key
[key.to_s[1..-1].to_sym,
if variable.respond_to? <:some_method> then
hashify variable
else
variable
end
]
}]
end # }}}

- 1,316
- 1
- 11
- 19
To do this without Rails, a clean way is to store attributes on a constant.
class Gift
ATTRIBUTES = [:name, :price]
attr_accessor(*ATTRIBUTES)
end
And then, to convert an instance of Gift
to a Hash
, you can:
class Gift
...
def to_h
ATTRIBUTES.each_with_object({}) do |attribute_name, memo|
memo[attribute_name] = send(attribute_name)
end
end
end
This is a good way to do this because it will only include what you define on attr_accessor
, and not every instance variable.
class Gift
ATTRIBUTES = [:name, :price]
attr_accessor(*ATTRIBUTES)
def create_random_instance_variable
@xyz = 123
end
def to_h
ATTRIBUTES.each_with_object({}) do |attribute_name, memo|
memo[attribute_name] = send(attribute_name)
end
end
end
g = Gift.new
g.name = "Foo"
g.price = 5.25
g.to_h
#=> {:name=>"Foo", :price=>5.25}
g.create_random_instance_variable
g.to_h
#=> {:name=>"Foo", :price=>5.25}

- 6,563
- 4
- 31
- 44
I started using structs to make easy to hash conversions. Instead of using a bare struct I create my own class deriving from a hash this allows you to create your own functions and it documents the properties of a class.
require 'ostruct'
BaseGift = Struct.new(:name, :price)
class Gift < BaseGift
def initialize(name, price)
super(name, price)
end
# ... more user defined methods here.
end
g = Gift.new('pearls', 20)
g.to_h # returns: {:name=>"pearls", :price=>20}

- 24,223
- 14
- 73
- 76
Following Nate's answer which I haven't been able to compile:
Option 1
class Object
def to_hash
instance_variables.map{ |v| Hash[v.to_s.delete("@").to_sym, instance_variable_get(v)] }.inject(:merge)
end
end
And then you call it like that:
my_object.to_hash[:my_variable_name]
Option 2
class Object
def to_hash
instance_variables.map{ |v| Hash[v.to_s.delete("@"), instance_variable_get(v)] }.inject(:merge)
end
end
And then you call it like that:
my_object.to_hash["my_variable_name"]

- 4,278
- 40
- 52