DEV Community

Akshay Khot
Akshay Khot

Posted on • Originally published at akshaykhot.com

3 2

How to Convert a Ruby Object to Hash

Let's say you have a Product object with properties @name = "Table" & @price = 10. What's the best way in Rails to convert this object to the Hash { name: "Table", price: 10 }?

Why?

Earlier this evening, I was trying to write an integration test to post some data to the server. The ActiveRecord model I was trying to create had many properties, so my params object grew quite a bit.

post records_path, params: { record: { attr_one: "", attr_two: "", ..., attr_n: "" } }
Enter fullscreen mode Exit fullscreen mode

However, I was using FactoryBot for testing, and could easily create a throwaway object using a factory.

record = build(:record)
Enter fullscreen mode Exit fullscreen mode

Now only if there was a simple way to transform this record object to a hash with the property names as keys and their values as the hash values.

It turns out, there are a few ways to achieve this.

The as_json Method

The as_json method converts a model to a hash, containing the attributes with their names as keys and the values of the attributes as values

user = User.find(1)
user.as_json
# => { "id" => 1, "name" => "Konata Izumi", "age" => 16 }
Enter fullscreen mode Exit fullscreen mode

Additionally, you can include the model itself as the root of the object.

user = User.find(1)
user.as_json(root: true)
# => { "user" => { "id" => 1, "name" => "Konata Izumi", "age" => 16 } }
Enter fullscreen mode Exit fullscreen mode

This method also gives you more control over the resulting JSON representation. For example, you can use the :only and :except options to select which attributes you want to include and skip, respectively. For more details, refer the documentation.

Using this method, I simplified my code to:

post records_path, params: build(:record).as_json(root: true)
Enter fullscreen mode Exit fullscreen mode

The attributes Method

The ActiveRecord#attributes is another method you can use. Given an active record, attributes returns a hash of all the attributes with their names as keys and the values of the attributes as values.

class Person < ActiveRecord::Base
end

person = Person.create(name: 'Francesco', age: 22)
person.attributes
# => {"id"=>3, "created_at"=>Sun, 21 Oct 2012 04:53:04, "updated_at"=>Sun, 21 Oct 2012 04:53:04, "name"=>"Francesco", "age"=>22}
Enter fullscreen mode Exit fullscreen mode

The attributes method returns a hash where all the keys are strings. If you want, it's easy to symbolize the hash using the aptly named symbolize_keys method or its alias to_options.

hash = { 'name' => 'Rob', 'age' => '28' }

hash.symbolize_keys
# => {:name=>"Rob", :age=>"28"}
Enter fullscreen mode Exit fullscreen mode

Using these methods, I refactored my code to:

post records_path, params: { record: build(:record).attributes.to_options }
Enter fullscreen mode Exit fullscreen mode

The Ruby Way

If you are looking for a plain Ruby solution, you can do this using metaprogramming. For this, you will need two methods:

  1. instance_variables returns an array of object's instance variables.
  2. instance_variable_get returns the value of the instance variable, given the variable name.

With that, you could do something like this:

hash = Hash.new
record.instance_variables.each do |v| 
  hash[v.to_s.delete("@")] = record.instance_variable_get(v) 
end
Enter fullscreen mode Exit fullscreen mode

What do you think?

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more