How to "pretty" format JSON output in Ruby on Rails
Solution 1
Use the pretty_generate()
function, built into later versions of JSON. For example:
require 'json'
my_object = { :array => [1, 2, 3, { :sample => "hash"} ], :foo => "bar" }
puts JSON.pretty_generate(my_object)
Which gets you:
{
"array": [
1,
2,
3,
{
"sample": "hash"
}
],
"foo": "bar"
}
Solution 2
The <pre>
tag in HTML, used with JSON.pretty_generate
, will render the JSON pretty in your view. I was so happy when my illustrious boss showed me this:
<% if @data.present? %>
<pre><%= JSON.pretty_generate(@data) %></pre>
<% end %>
Solution 3
Thanks to Rack Middleware and Rails 3 you can output pretty JSON for every request without changing any controller of your app. I have written such middleware snippet and I get nicely printed JSON in browser and curl
output.
class PrettyJsonResponse
def initialize(app)
@app = app
end
def call(env)
status, headers, response = @app.call(env)
if headers["Content-Type"] =~ /^application\/json/
obj = JSON.parse(response.body)
pretty_str = JSON.pretty_unparse(obj)
response = [pretty_str]
headers["Content-Length"] = pretty_str.bytesize.to_s
end
[status, headers, response]
end
end
The above code should be placed in app/middleware/pretty_json_response.rb
of your Rails project.
And the final step is to register the middleware in config/environments/development.rb
:
config.middleware.use PrettyJsonResponse
I don't recommend to use it in production.rb
. The JSON reparsing may degrade response time and throughput of your production app. Eventually extra logic such as 'X-Pretty-Json: true' header may be introduced to trigger formatting for manual curl requests on demand.
(Tested with Rails 3.2.8-5.0.0, Ruby 1.9.3-2.2.0, Linux)
Solution 4
If you want to:
- Prettify all outgoing JSON responses from your app automatically.
- Avoid polluting Object#to_json/#as_json
- Avoid parsing/re-rendering JSON using middleware (YUCK!)
- Do it the RAILS WAY!
Then ... replace the ActionController::Renderer for JSON! Just add the following code to your ApplicationController:
ActionController::Renderers.add :json do |json, options|
unless json.kind_of?(String)
json = json.as_json(options) if json.respond_to?(:as_json)
json = JSON.pretty_generate(json, options)
end
if options[:callback].present?
self.content_type ||= Mime::JS
"#{options[:callback]}(#{json})"
else
self.content_type ||= Mime::JSON
json
end
end
Solution 5
Check out Awesome Print. Parse the JSON string into a Ruby Hash, then display it with ap
like so:
require "awesome_print"
require "json"
json = '{"holy": ["nested", "json"], "batman!": {"a": 1, "b": 2}}'
ap(JSON.parse(json))
With the above, you'll see:
{
"holy" => [
[0] "nested",
[1] "json"
],
"batman!" => {
"a" => 1,
"b" => 2
}
}
Awesome Print will also add some color that Stack Overflow won't show you.
JP Richardson
https://www.exodus.com - all-in-one app to secure, manage and exchange blockchain assets like Bitcoin and Ethereum.
Updated on July 30, 2022Comments
-
JP Richardson almost 2 years
I would like my JSON output in Ruby on Rails to be "pretty" or nicely formatted.
Right now, I call
to_json
and my JSON is all on one line. At times this can be difficult to see if there is a problem in the JSON output stream.Is there way to configure to make my JSON "pretty" or nicely formatted in Rails?
-
TheDeadSerious over 13 yearsNifty! I've put this into my ~/.irbrc: def json_pp(json) puts JSON.pretty_generate(JSON.parse(json)) end
-
iconoclast over 12 yearsTo make this useful in Rails, it seems that you should give an answer which includes code that can be used in the same context as
format.json { render :json => @whatever }
-
lambshaanxy over 12 yearsSurely prettyprinting should only be used for server-side debugging? If you stick the code above in a controller, you'll have tons of useless whitespace in all responses, which isn't even needed for client-side debugging as any tools worth their salt (eg. Firebug) already handle prettyprinting JSON.
-
iconoclast over 12 years@jpatokal: you may consider there to be other better options, but the question was how to get this to work in Rails. Saying "you don't want to do that in Rails" is a non-answer. Obviously a lot of people want to do it in Rails.
-
lambshaanxy over 12 yearsThe original poster said nothing about where in a Rails app he wants to use this, so I answered with a line of Ruby that will work anywhere. To use it to generate the JSON response in a Rails controller, you already answered your own question:
format.json { render :json => JSON.pretty_generate(my_json) }
. -
Ammo Goettsch over 10 yearsHow are you getting around ActiveSupport's redefinition of to_json? This keeps me from pretty printing while ActiveSupport is present.
-
gertas over 10 yearsI don't care really, to_json, as_json, jbuilder which I use mostly - whatever, middleware transforms any JSON output. I try to avoid opening classes whenever possible.
-
Sheharyar over 10 years@jpatokal's comment above for
render
didn't work for me. I had to modify it a bit:render :json => JSON.pretty_generate(JSON.parse(my_json))
-
lambshaanxy over 10 yearsIf you have to call
JSON.parse
on it, yourmy_json
is a string, not JSON! -
Kimmo Lehto over 10 yearsI had to change the parse line to
obj = JSON.parse(response.body.first)
to make it work. -
gertas over 10 yearsJust tried your advice and it failed as
body
is a string under both Thin and Passenger in development mode. RoR3/4 and Ruby 2.0. Theresponse.body
is apidock.com/rails/v3.2.13/ActionDispatch/Response/body -
elsurudo over 10 yearsWorks great in Rails 4 as well... thanks! I prefer this to the more library-specific methods (as in the accepted answer). Since you should only use this in dev mode anyways, the performance hit isn't a big deal.
-
Matthew Brown almost 10 yearsI like this one, and I am looking forward to using it.
-
Wayne Conrad over 9 yearsSee stackoverflow.com/a/26491790/238886 for an evolution of this solution that does not call
response.body
and should work in any Rack app. -
nornagon about 9 yearsThis is awesome, but it actually causes dates/times to render differently: gist.github.com/nornagon/9c24b68bd6d3e871add3
-
Christopher Oezbek almost 9 yearsSeveral problems with this: (1) JSON.pretty_generate requires
json.respond_to?(:to_h)
or:to_hash
. (2) pretty_generate can choke on things that to_json does not. -
counterbeing about 8 yearsWorking wonderfully for me with rails 4.2.5 and Puma as my server. Absolutely lovely. Thank you!
-
panteo almost 8 yearsIn Rails 5 I had to change
Rack::Utils.bytesize(pretty_str).to_s
topretty_str.bytesize.to_s
and it works great! -
Johnny Wong over 7 yearsto get a string from
pp
instead of printing to standard output, useUser.first.as_json.pretty_inspect
. Works well for me. -
Xavier over 7 yearsFantastic, thanks! I made a gem out of this: github.com/zeiv/rails_pretty_json
-
Lev Lukomsky over 6 yearsThere is also handy method in console
jj
, which pretty prints json object to STDOUT -
ConorSheehan1 over 5 years@nornagon I haven't applied this change and I'm getting the same difference you saw between .to_json and pretty_generate. I only see it in a rails console, not plain irb. I think this could be a general rails thing, nothing to do with this patch. Also, Time.parse returns the same result when you convert the string back to time for both formats. It'd only be a minor inconvenience when searching logs for time stamps, but if you're grepping anyway adding a few \s+ isn't really a big deal.
-
ConorSheehan1 over 5 years@nornagon looks like the issue you saw was ActiveSupport's redefinition of to_json, as mentioned in Ammo Goettsch's comment
-
sekmo over 5 yearsIs there a better way to do something like
JSON.pretty_generate(JSON.parse(json_stuff))
if you have a json and not a hash?