Rails Object to hash

I have the following object that has been created

@post = Post.create(:name => 'test', :post_number => 20, :active => true)

Once this is saved, I want to be able to get the object back to a hash, e.g. by doing somthing like:

@object.to_hash

How is this possible from within rails?


Solution 1:

If you are looking for only attributes, then you can get them by:

@post.attributes

Note that this calls ActiveModel::AttributeSet.to_hash every time you invoke it, so if you need to access the hash multiple times you should cache it in a local variable:

attribs = @post.attributes

Solution 2:

In most recent version of Rails (can't tell which one exactly though), you could use the as_json method :

@post = Post.first
hash = @post.as_json
puts hash.pretty_inspect

Will output :

{ 
  :name => "test",
  :post_number => 20,
  :active => true
}

To go a bit further, you could override that method in order to customize the way your attributes appear, by doing something like this :

class Post < ActiveRecord::Base
  def as_json(*args)
    {
      :name => "My name is '#{self.name}'",
      :post_number => "Post ##{self.post_number}",
    }
  end
end

Then, with the same instance as above, will output :

{ 
  :name => "My name is 'test'",
  :post_number => "Post #20"
}

This of course means you have to explicitly specify which attributes must appear.

Hope this helps.

EDIT :

Also you can check the Hashifiable gem.

Solution 3:

@object.as_json

as_json has very flexible way to configure complex object according to model relations

EXAMPLE

Model campaign belongs to shop and has one list

Model list has many list_tasks and each of list_tasks has many comments

We can get one json which combines all those data easily.

@campaign.as_json(
    {
        except: [:created_at, :updated_at],
        include: {
            shop: {
                except: [:created_at, :updated_at, :customer_id],
                include: {customer: {except: [:created_at, :updated_at]}}},
            list: {
                except: [:created_at, :updated_at, :observation_id],
                include: {
                    list_tasks: {
                        except: [:created_at, :updated_at],
                        include: {comments: {except: [:created_at, :updated_at]}}
                    }
                }
            },
        },
        methods: :tags
    })

Notice methods: :tags can help you attach any additional object which doesn't have relations with others. You just need to define a method with name tags in model campaign. This method should return whatever you need (e.g. Tags.all)

Official documentation for as_json

Solution 4:

You can get the attributes of a model object returned as a hash using either

@post.attributes

or

@post.as_json

as_json allows you to include associations and their attributes as well as specify which attributes to include/exclude (see documentation). However, if you only need the attributes of the base object, benchmarking in my app with ruby 2.2.3 and rails 4.2.2 demonstrates that attributes requires less than half as much time as as_json.

>> p = Problem.last
 Problem Load (0.5ms)  SELECT  "problems".* FROM "problems"  ORDER BY "problems"."id" DESC LIMIT 1
=> #<Problem id: 137, enabled: true, created_at: "2016-02-19 11:20:28", updated_at: "2016-02-26 07:47:34"> 
>>
>> p.attributes
=> {"id"=>137, "enabled"=>true, "created_at"=>Fri, 19 Feb 2016 11:20:28 UTC +00:00, "updated_at"=>Fri, 26 Feb 2016 07:47:34 UTC +00:00}
>>
>> p.as_json
=> {"id"=>137, "enabled"=>true, "created_at"=>Fri, 19 Feb 2016 11:20:28 UTC +00:00, "updated_at"=>Fri, 26 Feb 2016 07:47:34 UTC +00:00}
>>
>> n = 1000000
>> Benchmark.bmbm do |x|
?>   x.report("attributes") { n.times { p.attributes } }
?>   x.report("as_json")    { n.times { p.as_json } }
>> end
Rehearsal ----------------------------------------------
attributes   6.910000   0.020000   6.930000 (  7.078699)
as_json     14.810000   0.160000  14.970000 ( 15.253316)
------------------------------------ total: 21.900000sec

             user     system      total        real
attributes   6.820000   0.010000   6.830000 (  7.004783)
as_json     14.990000   0.050000  15.040000 ( 15.352894)