Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails Object to hash

People also ask

What is To_hash in Ruby?

Overview. The to_hash() method is a hash class method that returns the hash representation of the hash itself.

How do you merge hashes in Ruby?

We can merge two hashes using the merge() method. When using the merge() method: Each new entry is added to the end. Each duplicate-key entry's value overwrites the previous value.

What is an attribute in Ruby?

Attributes are specific properties of an object. Methods are capabilities of an object. In Ruby all instance variables (attributes) are private by default. It means you don't have access to them outside the scope of the instance itself. The only way to access the attribute is using an accessor method.


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

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.


@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


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)

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.


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

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