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)