409

How to convert a ruby hash object to JSON? So I am trying this example below & it doesn't work?

I was looking at the RubyDoc and obviously Hash object doesn't have a to_json method. But I am reading on blogs that Rails supports active_record.to_json and also supports hash#to_json. I can understand ActiveRecord is a Rails object, but Hash is not native to Rails, it's a pure Ruby object. So in Rails you can do a hash.to_json, but not in pure Ruby??

car = {:make => "bmw", :year => "2003"} car.to_json 
1
  • beware though, if the object on which you call to_json is already json, you'll get a mess: { foo: "bar" }.to_json.to_json
    – duhaime
    CommentedOct 21, 2022 at 0:48

4 Answers 4

654

One of the numerous niceties of Ruby is the possibility to extend existing classes with your own methods. That's called "class reopening" or monkey-patching (the meaning of the latter can vary, though).

So, take a look here:

car = {:make => "bmw", :year => "2003"} # => {:make=>"bmw", :year=>"2003"} car.to_json # NoMethodError: undefined method `to_json' for {:make=>"bmw", :year=>"2003"}:Hash # from (irb):11 # from /usr/bin/irb:12:in `<main>' require 'json' # => true car.to_json # => "{"make":"bmw","year":"2003"}" 

As you can see, requiring json has magically brought method to_json to our Hash.

7
  • 2
    all i can say is wow :) also thanks a lot!! so basically i was able to extend the json class dynamically??
    – kapso
    CommentedJul 6, 2010 at 16:49
  • 1
    I tried the same thing with Ruby object and it does not work?? >> require 'json' => true >> class Person >> attr_accessor :fname, :lname >> end => nil >> p = Person.new => #<Person:0x101155f70> >> p.fname = "Bill" => "Bill" >> p.lname = "Shine" => "Shine" >> p.to_json => "\"#<Person:0x101155f70>\""
    – kapso
    CommentedJul 6, 2010 at 16:56
  • 11
    No, no, someone has to code how the object of an arbitrary class should be serialized to JSON. They did it for Hash and Array classes in json gem, but your class Person is just a plain Object. But you can inherit Hash instead. You can open a new question if you don't manage.CommentedJul 6, 2010 at 17:05
  • thanks. here's the new question, any help would be appreciated. Thanks. stackoverflow.com/questions/3226054/…
    – kapso
    CommentedJul 12, 2010 at 5:25
  • You're showing what looks to be IRB type output. I was trying to get hash#to_json to work for DateTime object. Thanks to this post I got it. But I did inspect with p date_json This is what I got for a true string "{\"year\":2013,\"mon\":7,\"mday\":16,\"hour\":13,\"min\":54,\"sec\":32,\"zone\":\"-05:00\",\"offset\":-18000}" so you may see that it is making the key symbols as strings and of course that data is unchanged. Thanks again. Sorry I'm so late though.CommentedJul 16, 2013 at 19:00
22
require 'json/ext' # to use the C based extension instead of json/pure puts {hash: 123}.to_json 
    19

    You can also use JSON.generate:

    require 'json' JSON.generate({ foo: "bar" }) => "{\"foo\":\"bar\"}" 

    Or its alias, JSON.unparse:

    require 'json' JSON.unparse({ foo: "bar" }) => "{\"foo\":\"bar\"}" 
    1
    • JSON.generate only allows objects or arrays to be converted to JSON syntax. to_json, however, accepts many Ruby classes even though it acts only as a method for serialization: 1.to_json # => "1". Docs here: ruby-doc.org/stdlib-2.6.3/libdoc/json/rdoc/JSON.html
      – bkunzi01
      CommentedJul 13, 2020 at 20:22
    19

    Add the following line on the top of your file

    require 'json' 

    Then you can use:

    car = {:make => "bmw", :year => "2003"} car.to_json 

    Alternatively, you can use:

    JSON.generate({:make => "bmw", :year => "2003"}) 

      Start asking to get answers

      Find the answer to your question by asking.

      Ask question

      Explore related questions

      See similar questions with these tags.