Rails Object to hash

Ruby on-RailsRuby

Ruby on-Rails Problem Overview


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?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

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 - Ruby on-Rails

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 - Ruby on-Rails

@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 - Ruby on-Rails

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)

Solution 5 - Ruby on-Rails

You could definitely use the attributes to return all attributes but you could add an instance method to Post, call it "to_hash" and have it return the data you would like in a hash. Something like

def to_hash
 { name: self.name, active: true }
end

Solution 6 - Ruby on-Rails

There are some great suggestions here.

I think it's worth noting that you can treat an ActiveRecord model as a hash like so:

@customer = Customer.new( name: "John Jacob" )
@customer.name    # => "John Jacob"
@customer[:name]  # => "John Jacob"
@customer['name'] # => "John Jacob"

Therefore, instead of generating a hash of the attributes, you can use the object itself as a hash.

Solution 7 - Ruby on-Rails

not sure if that's what you need but try this in ruby console:

h = Hash.new
h["name"] = "test"
h["post_number"] = 20
h["active"] = true
h

obviously it will return you a hash in console. if you want to return a hash from within a method - instead of just "h" try using "return h.inspect", something similar to:

def wordcount(str)
  h = Hash.new()
  str.split.each do |key|
    if h[key] == nil
      h[key] = 1
    else
      h[key] = h[key] + 1
    end
  end
  return h.inspect
end

Solution 8 - Ruby on-Rails

My solution:

Hash[ post.attributes.map{ |a| [a, post[a]] } ]

Solution 9 - Ruby on-Rails

Swanand's answer is great.

if you are using FactoryGirl, you can use its build method to generate the attribute hash without the key id. e.g.

build(:post).attributes

Solution 10 - Ruby on-Rails

Old question, but heavily referenced ... I think most people use other methods, but there is infact a to_hash method, it has to be setup right. Generally, pluck is a better answer after rails 4 ... answering this mainly because I had to search a bunch to find this thread or anything useful & assuming others are hitting the same problem...

Note: not recommending this for everyone, but edge cases!


From the ruby on rails api ... http://api.rubyonrails.org/classes/ActiveRecord/Result.html ...

This class encapsulates a result returned from calling #exec_query on any database connection adapter. For example:

result = ActiveRecord::Base.connection.exec_query('SELECT id, title, body FROM posts')
result # => #<ActiveRecord::Result:0xdeadbeef>

...

# Get an array of hashes representing the result (column => value):
result.to_hash
# => [{"id" => 1, "title" => "title_1", "body" => "body_1"},
      {"id" => 2, "title" => "title_2", "body" => "body_2"},
      ...
     ] ...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionben morganView Question on Stackoverflow
Solution 1 - Ruby on-RailsSwanandView Answer on Stackoverflow
Solution 2 - Ruby on-RailsRafView Answer on Stackoverflow
Solution 3 - Ruby on-RailsSergiy SeletskyyView Answer on Stackoverflow
Solution 4 - Ruby on-RailsJohn ColeView Answer on Stackoverflow
Solution 5 - Ruby on-RailsCurtis EdmondView Answer on Stackoverflow
Solution 6 - Ruby on-RailsJeffrey HarringtonView Answer on Stackoverflow
Solution 7 - Ruby on-RailsYuriView Answer on Stackoverflow
Solution 8 - Ruby on-RailsfayvorView Answer on Stackoverflow
Solution 9 - Ruby on-RailsSiweiView Answer on Stackoverflow
Solution 10 - Ruby on-RailsMirv - MattView Answer on Stackoverflow