54

I would like to do something like this:

require 'json'

class Person
attr_accessor :fname, :lname
end

p = Person.new
p.fname = "Mike"
p.lname = "Smith"

p.to_json

Is it possible?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
kapso
  • 11,703
  • 16
  • 58
  • 76

3 Answers3

48

Yes, you can do it with to_json.

You may need to require 'json' if you're not running Rails.

coreyward
  • 77,547
  • 20
  • 137
  • 166
Salil
  • 46,566
  • 21
  • 122
  • 156
  • 1
    With Rails it's not necessary to use `require 'json'`, but with regular Ruby code it's likely to be necessary. [JSON is part of Ruby's Standard Library](https://ruby-doc.org/stdlib/libdoc/json/rdoc/index.html) so it comes with the language. – the Tin Man May 17 '17 at 21:00
37

To make your Ruby class JSON-friendly without touching Rails, you'd define two methods:

  • to_json, which returns a JSON object
  • as_json, which returns a hash representation of the object

When your object responds properly to both to_json and as_json, it can behave properly even when it is nested deep inside other standard classes like Array and/or Hash:

#!/usr/bin/env ruby

require 'json'

class Person

    attr_accessor :fname, :lname

    def as_json(options={})
        {
            fname: @fname,
            lname: @lname
        }
    end

    def to_json(*options)
        as_json(*options).to_json(*options)
    end

end

p = Person.new
p.fname = "Mike"
p.lname = "Smith"

# case 1
puts p.to_json                  # output: {"fname":"Mike","lname":"Smith"}

# case 2
puts [p].to_json                # output: [{"fname":"Mike","lname":"Smith"}]

# case 3
h = {:some_key => p}
puts h.to_json                  # output: {"some_key":{"fname":"Mike","lname":"Smith"}}

puts JSON.pretty_generate(h)    # output
                                # {
                                #   "some_key": {
                                #     "fname": "Mike",
                                #     "lname": "Smith"
                                #   }
                                # }

Also see "Using custom to_json method in nested objects".

Community
  • 1
  • 1
Dmitry Shevkoplyas
  • 6,163
  • 3
  • 27
  • 28
22

Try it. If you're using Ruby on Rails (and the tags say you are), I think this exact code should work already, without requiring anything.

Rails supports JSON output from controllers, so it already pulls in all of the JSON serialization code that you will ever need. If you're planning to output this data through a controller, you might be able to save time by just writing

render :json => @person
Matchu
  • 83,922
  • 18
  • 153
  • 160