Comment puis-je" pretty " formater ma sortie JSON en Ruby on Rails?
j'aimerais que ma sortie JSON dans Ruby on Rails soit" jolie " ou joliment formatée.
en ce moment, j'appelle to_json
et mon JSON est sur une seule ligne. Parfois, cela peut être difficile de voir s'il y a un problème dans le flux de sortie JSON.
y a-t-il moyen de configurer ou une méthode pour rendre mon JSON" joli " ou joliment formaté dans les Rails?
16 réponses
utilise la fonction pretty_generate()
, intégrée dans les versions ultérieures de JSON. Par exemple:
require 'json'
my_object = { :array => [1, 2, 3, { :sample => "hash"} ], :foo => "bar" }
puts JSON.pretty_generate(my_object)
Qui vous permet de vous:
{
"array": [
1,
2,
3,
{
"sample": "hash"
}
],
"foo": "bar"
}
merci à Rack Middleware et Rails 3 vous pouvez produire pretty JSON pour chaque demande sans changer n'importe quel contrôleur de votre application. J'ai écrit un tel middleware snippet et je reçois JSON joliment imprimé dans le navigateur et curl
sortie.
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
le code ci-dessus doit être placé dans app/middleware/pretty_json_response.rb
de votre projet Rails.
Et la dernière étape est d'enregistrer le middleware dans config/environments/development.rb
:
config.middleware.use PrettyJsonResponse
je n'ai pas il est recommandé de l'utiliser dans production.rb
. La réparation JSON peut dégrader le temps de réponse et le débit de votre application de production. Éventuellement, une logique supplémentaire telle que l'en-tête 'X-Pretty-JSON: true' peut être introduite pour déclencher le formatage des requêtes curl manuelles à la demande.
(Testé avec les Rails 3.2.8-5.0.0, Ruby 1.9.3-2.2.0, Linux)
la balise <pre>
en HTML, utilisée avec JSON.pretty_generate
, rendra le JSON pretty à votre avis. J'étais tellement heureux quand mon illustre patron m'a montré ceci:
<% if !@data.blank? %>
<pre><%= JSON.pretty_generate(@data) %></pre>
<% end %>
si vous voulez:
- Prétifiez toutes les réponses JSON sortantes de votre application automatiquement.
- éviter de polluer L'objet # to_json / # as_json
- éviter d'analyser / re-rendre JSON en utilisant middleware (YUCK!)
- Faire les RAILS de CHEMIN!
alors ... remplacer le contrôleur ActionController:: Renderer pour JSON! Il suffit d'ajouter le code suivant à votre 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
Check out awesome_print . Analysez la chaîne JSON en un Hash Ruby, puis affichez-le avec awesome_print comme suit:
require "awesome_print"
require "json"
json = '{"holy": ["nested", "json"], "batman!": {"a": 1, "b": 2}}'
ap(JSON.parse(json))
avec ce qui précède, vous verrez:
{
"holy" => [
[0] "nested",
[1] "json"
],
"batman!" => {
"a" => 1,
"b" => 2
}
}
awesome_print va aussi ajouter une couleur que le débordement de la pile ne vous montrera pas:)
largage D'un objet ActiveRecord à JSON (dans la console Rail):
pp User.first.as_json
# => {
"id" => 1,
"first_name" => "Polar",
"last_name" => "Bear"
}
si vous (comme moi) trouvez que l'option pretty_generate
intégrée dans la bibliothèque JSON de Ruby n'est pas" assez", je recommande ma propre pierre NeatJSON
pour votre formatage.
pour l'utiliser gem install neatjson
et ensuite utiliser JSON.neat_generate
au lieu de JSON.pretty_generate
.
comme pp
de Ruby, il gardera les objets et les tableaux sur une seule ligne quand ils conviennent, mais les enveloppera à plusieurs si nécessaire. Par exemple:
{
"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?"}
]
}
il supporte également une variété de options de formatage pour personnaliser davantage votre sortie. Par exemple, combien d'espaces avant/après les virgules? Avant / après virgule? Dans les consoles des tableaux et des objets? Voulez-vous trier les clés de votre objet? Tu veux que les colons soient alignés?
utilisant <pre>
code html et pretty_generate
est un bon truc:
<%
require 'json'
hash = JSON[{hey: "test", num: [{one: 1, two: 2, threes: [{three: 3, tthree: 33}]}]}.to_json]
%>
<pre>
<%= JSON.pretty_generate(hash) %>
</pre>
Voici une solution middleware modifiée de cette excellente réponse de @gertas . Cette solution n'est pas spécifique aux Rails, elle devrait fonctionner avec n'importe quelle application de crémaillère.
la technique middleware utilisée ici, en utilisant #each, est expliquée à ASCIIcasts 151: Rack Middleware par Eifion Bedford.
ce code va dans 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
pour l'allumer, ajoutez ceci à config/environments/test.rb et config/environments/développement.rb:
config.middleware.use "PrettyJsonResponse"
comme avertit @gertas dans sa version de cette solution, éviter de l'utiliser dans la production. C'est un peu lent.
éprouvé avec des Rails 4.1.6.
#At Controller
def branch
@data = Model.all
render json: JSON.pretty_generate(@data.as_json)
end
voici ma solution que j'ai dérivé d'autres messages au cours de ma propre recherche.
cela vous permet d'envoyer la sortie pp et jj dans un fichier au besoin.
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
j'ai utilisé le Gem CodeRay et il fonctionne assez bien. Le format comprend des couleurs et il reconnaît beaucoup de formats différents.
Je l'ai utilisé sur un bijou qui peut être utilisé pour déboguer les API rails et il fonctionne assez bien.
soit dit en passant, le joyau s'appelle "api_explorer" ( http://www.github.com/toptierlabs/api_explorer )
si vous cherchez à implémenter rapidement cette action dans un contrôleur rail pour envoyer une réponse JSON:
def index
my_json = '{ "key": "value" }'
render json: JSON.pretty_generate( JSON.parse my_json )
end
j'utilise ce qui suit car je trouve les en-têtes, le statut et la sortie JSON utiles comme ensemble. La routine d'appel est débitée sur recommandation d'une présentation railscasts à: http://railscasts.com/episodes/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
si vous utilisez RABL vous pouvez configurer comme décrit ici pour utiliser JSON.pretty_generate:
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
un problème avec L'utilisation de JSON.pretty_generate est que les validateurs de schéma JSON ne seront plus satisfaits de vos chaînes datetime. Vous pouvez les corriger dans votre config/initializers/rabl_config.rb avec:
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