Wie kann ich meine JSON-Ausgabe in Ruby on Rails „ziemlich“ formatieren?
-
01-07-2019 - |
Frage
Ich möchte, dass meine JSON-Ausgabe in Ruby on Rails „hübsch“ oder gut formatiert ist.
Im Moment rufe ich an to_json
und mein JSON ist alles in einer Zeile.Manchmal kann es schwierig sein, ein Problem im JSON-Ausgabestream zu erkennen.
Gibt es eine Möglichkeit zum Konfigurieren oder eine Methode, um mein JSON in Rails „hübsch“ oder schön formatiert zu machen?
Lösung
Mit der pretty_generate()
Funktion, in späteren Versionen von JSON gebaut. Zum Beispiel:
require 'json'
my_object = { :array => [1, 2, 3, { :sample => "hash"} ], :foo => "bar" }
puts JSON.pretty_generate(my_object)
Welche bekommt man:
{
"array": [
1,
2,
3,
{
"sample": "hash"
}
],
"foo": "bar"
}
Andere Tipps
Dank Rack-Middleware und Rails 3 können Sie die Ausgabe ziemlich JSON für jede Anfrage ohne jede Steuerung Ihrer Anwendung zu ändern. Ich habe solche Middleware-Schnipsel geschrieben und ich bekomme schön JSON in Browser und curl
Ausgabe gedruckt.
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
Der obige Code sollte in app/middleware/pretty_json_response.rb
Ihrem Rails-Projekt platziert werden.
Und der letzte Schritt ist die Middleware in config/environments/development.rb
registrieren:
config.middleware.use PrettyJsonResponse
Ich empfehle nicht, es in production.rb
zu verwenden . Die JSON neuparsen kann die Reaktionszeit und Durchsatz Ihrer Produktions App verschlechtern. Schließlich zusätzliche Logik wie ‚X-Pretty-Json: true‘. Header eingeführt werden kann, die Formatierung für die manuellen curl Anfragen auf Anfrage auslösen
(Getestet mit Rails 3.2.8-5.0.0 Ruby 1.9.3-2.2.0, Linux)
Das <pre>
-Tag in HTML, mit JSON.pretty_generate
verwendet, wird die JSON ziemlich Ihrer Ansicht nach machen. Ich war so glücklich, als mein berühmter Chef zeigte mir dies:
<% if @data.present? %>
<pre><%= JSON.pretty_generate(@data) %></pre>
<% end %>
Wenn Sie wollen:
- Prettify alle abgehenden JSON Antworten von Ihrer Anwendung automatisch.
- Vermeiden Objekt # to_json verschmutzen / # as_json
- Vermeiden Parsing / Re-Rendering JSON mit Middleware (igitt!)
- Machen Sie es den Schienen WAY!
Dann ... ersetzen Sie die Action :: Renderer für JSON! Fügen Sie einfach den folgenden Code auf Ihre Application:
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
Schauen Sie sich awesome_print . Analysieren Sie den JSON-String in einen Ruby-Hash, es zeigt dann mit awesome_print etwa so:
require "awesome_print"
require "json"
json = '{"holy": ["nested", "json"], "batman!": {"a": 1, "b": 2}}'
ap(JSON.parse(json))
Mit dem oben, sehen Sie:
{
"holy" => [
[0] "nested",
[1] "json"
],
"batman!" => {
"a" => 1,
"b" => 2
}
}
awesome_print fügt auch etwas Farbe, die Stack-Überlauf wird nicht zeigen:)
Dumping ein Activerecord-Objekt JSON (in der Rails-Konsole):
pp User.first.as_json
# => {
"id" => 1,
"first_name" => "Polar",
"last_name" => "Bear"
}
Wenn Sie (wie ich) finden, dass die pretty_generate
Option in Rubys JSON Bibliothek gebaut ist nicht „schön“ genug, empfehle ich meine eigene NeatJSON
Juwel für Ihre Formatierung.
Um es zu nutzen gem install neatjson
und verwenden Sie dann JSON.neat_generate
statt JSON.pretty_generate
.
Wie Rubys pp
es Objekte und Arrays auf einer Linie halten, wenn sie passen, aber wickelt, um mehr nach Bedarf. Zum Beispiel:
{
"navigation.createroute.poi":[
{"text":"Lay in a course to the Hilton","params":{"poi":"Hilton"}},
{"text":"Take me to the airport","params":{"poi":"airport"}},
{"text":"Let's go to IHOP","params":{"poi":"IHOP"}},
{"text":"Show me how to get to The Med","params":{"poi":"The Med"}},
{"text":"Create a route to Arby's","params":{"poi":"Arby's"}},
{
"text":"Go to the Hilton by the Airport",
"params":{"poi":"Hilton","location":"Airport"}
},
{
"text":"Take me to the Fry's in Fresno",
"params":{"poi":"Fry's","location":"Fresno"}
}
],
"navigation.eta":[
{"text":"When will we get there?"},
{"text":"When will I arrive?"},
{"text":"What time will I get to the destination?"},
{"text":"What time will I reach the destination?"},
{"text":"What time will it be when I arrive?"}
]
}
Es unterstützt auch eine Vielzahl von Formatierungsoptionen um Ihre Ausgabe anpassen. Zum Beispiel, wie viele Leerzeichen vor / nach Doppelpunkten? Vorher / Nachher Komma? Innerhalb der Klammern von Arrays und Objekte? Wollen Sie die Tasten Ihres Objekts sortieren? Wollen Sie die Doppelpunkte auf alle aufgereiht werden?
Mit <pre>
HTML-Code und pretty_generate
ist guter Trick:
<%
require 'json'
hash = JSON[{hey: "test", num: [{one: 1, two: 2, threes: [{three: 3, tthree: 33}]}]}.to_json]
%>
<pre>
<%= JSON.pretty_generate(hash) %>
</pre>
Hier ist eine Middleware-Lösung von Antwort dieser ausgezeichneten geändert durch @gertas . Diese Lösung ist nicht Rails spezifisch -. Es sollte mit jeder Rack-Anwendung arbeitet
Die Middleware-Technik hier verwendet wird, #each verwendet wird, wird erklärt unter ASCIIcasts 151: Rack-Middleware von Eifion Bedford.
Dieser Code geht in app / Middleware / pretty_json_response.rb :
class PrettyJsonResponse
def initialize(app)
@app = app
end
def call(env)
@status, @headers, @response = @app.call(env)
[@status, @headers, self]
end
def each(&block)
@response.each do |body|
if @headers["Content-Type"] =~ /^application\/json/
body = pretty_print(body)
end
block.call(body)
end
end
private
def pretty_print(json)
obj = JSON.parse(json)
JSON.pretty_unparse(obj)
end
end
Zum Einschalten, fügen Sie diese config / Umgebungen / test.rb und config / Umgebungen / development.rb:
config.middleware.use "PrettyJsonResponse"
Wie @gertas in seiner Version dieser Lösung warnt, vermeiden Sie es in der Produktion. Es ist etwas langsam.
Getestet mit Rails 4.1.6.
#At Controller
def branch
@data = Model.all
render json: JSON.pretty_generate(@data.as_json)
end
Hier ist meine Lösung, die ich von anderen Beiträgen während meiner eigenen Suche abgeleitet.
Auf diese Weise können Sie die Seiten und jj Ausgabe in eine Datei senden, je nach Bedarf.
require "pp"
require "json"
class File
def pp(*objs)
objs.each {|obj|
PP.pp(obj, self)
}
objs.size <= 1 ? objs.first : objs
end
def jj(*objs)
objs.each {|obj|
obj = JSON.parse(obj.to_json)
self.puts JSON.pretty_generate(obj)
}
objs.size <= 1 ? objs.first : objs
end
end
test_object = { :name => { first: "Christopher", last: "Mullins" }, :grades => [ "English" => "B+", "Algebra" => "A+" ] }
test_json_object = JSON.parse(test_object.to_json)
File.open("log/object_dump.txt", "w") do |file|
file.pp(test_object)
end
File.open("log/json_dump.txt", "w") do |file|
file.jj(test_json_object)
end
Ich habe das Gem CodeRay verwendet und es funktioniert ziemlich gut.Das Format umfasst Farben und erkennt viele verschiedene Formate.
Ich habe es auf einem Gem verwendet, das zum Debuggen von Rails-APIs verwendet werden kann, und es funktioniert ziemlich gut.
Der Edelstein heißt übrigens „api_explorer“ (http://www.github.com/toptierlabs/api_explorer)
Wenn Sie schauen, um schnell diese in einer Aktion Rails-Controller implementieren eine JSON-Antwort zu senden:
def index
my_json = '{ "key": "value" }'
render json: JSON.pretty_generate( JSON.parse my_json )
end
Ich benutze das folgende, wie ich die Header, Status und JSON Ausgabe nützlich als ein Satz. Der Aufruf Routine wird ausgebrochenen auf Empfehlung einer Railscasts Präsentation unter: http: // Railscasts .com / Episoden / 151-Rack-Middleware? autoplay = true
class LogJson
def initialize(app)
@app = app
end
def call(env)
dup._call(env)
end
def _call(env)
@status, @headers, @response = @app.call(env)
[@status, @headers, self]
end
def each(&block)
if @headers["Content-Type"] =~ /^application\/json/
obj = JSON.parse(@response.body)
pretty_str = JSON.pretty_unparse(obj)
@headers["Content-Length"] = Rack::Utils.bytesize(pretty_str).to_s
Rails.logger.info ("HTTP Headers: #{ @headers } ")
Rails.logger.info ("HTTP Status: #{ @status } ")
Rails.logger.info ("JSON Response: #{ pretty_str} ")
end
@response.each(&block)
end
end
Wenn Sie mit RABL können Sie es so konfigurieren, wie beschrieben hier JSON.pretty_generate zu verwenden:
class PrettyJson
def self.dump(object)
JSON.pretty_generate(object, {:indent => " "})
end
end
Rabl.configure do |config|
...
config.json_engine = PrettyJson if Rails.env.development?
...
end
Ein Problem bei JSON.pretty_generate ist, dass JSON Schema Validatoren nicht mehr mit Ihren Datetime Strings glücklich sein. Sie können die in Ihrem config / initializers / rabl_config.rb fix mit:
ActiveSupport::TimeWithZone.class_eval do
alias_method :orig_to_s, :to_s
def to_s(format = :default)
format == :default ? iso8601 : orig_to_s(format)
end
end
# example of use:
a_hash = {user_info: {type: "query_service", e_mail: "my@email.com", phone: "+79876543322"}, cars_makers: ["bmw", "mitsubishi"], car_models: [bmw: {model: "1er", year_mfc: 2006}, mitsubishi: {model: "pajero", year_mfc: 1997}]}
pretty_html = a_hash.pretty_html
# include this module to your libs:
module MyPrettyPrint
def pretty_html indent = 0
result = ""
if self.class == Hash
self.each do |key, value|
result += "#{key}: #{[Array, Hash].include?(value.class) ? value.pretty_html(indent+1) : value}"
end
elsif self.class == Array
result = "[#{self.join(', ')}]"
end
"#{result}"
end
end
class Hash
include MyPrettyPrint
end
class Array
include MyPrettyPrint
end
Pretty Druckvariante:
my_object = { :array => [1, 2, 3, { :sample => "hash"}, 44455, 677778, 9900 ], :foo => "bar", rrr: {"pid": 63, "state": false}}
puts my_object.as_json.pretty_inspect.gsub('=>', ': ')
Ergebnis:
{"array": [1, 2, 3, {"sample": "hash"}, 44455, 677778, 9900],
"foo": "bar",
"rrr": {"pid": 63, "state": false}}