Question

J'aimerais que ma sortie JSON dans Ruby on Rails soit "jolie". ou bien formaté.

À l'heure actuelle, j'appelle to_json et mon JSON est sur une seule ligne. Il peut parfois être difficile de savoir s’il existe un problème dans le flux de sortie JSON.

Existe-t-il un moyen de configurer ou une méthode pour rendre mon code JSON "jolie" ou bien formaté dans Rails?

Était-ce utile?

La solution

Utilisez la fonction pretty_generate () , intégrée aux 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)

Ce qui vous amène:

{
  "array": [
    1,
    2,
    3,
    {
      "sample": "hash"
    }
  ],
  "foo": "bar"
}

Autres conseils

Grâce à Rack Middleware et à Rails 3, vous pouvez générer de jolis JSON pour chaque requête sans changer aucun contrôleur de votre application. J'ai écrit un tel extrait de middleware et j'obtiens du JSON bien imprimé dans le navigateur et une sortie curl .

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 consiste à enregistrer le middleware dans config / environment / development.rb :

config.middleware.use PrettyJsonResponse

Je ne recommande pas de l'utiliser dans production.rb . Le reparsing JSON peut dégrader le temps de réponse et le débit de votre application de production. Finalement, une logique supplémentaire telle que l’en-tête 'X-Pretty-Json: true' peut être introduite pour déclencher le formatage des demandes de curl manuelles à la demande.

(testé avec 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 joli dans votre vue. J'étais si heureux quand mon illustre patron m'a montré ceci:

<% if @data.present? %>
   <pre><%= JSON.pretty_generate(@data) %></pre>
<% end %>

Si vous souhaitez:

  1. Confirmez automatiquement toutes les réponses JSON sortantes de votre application.
  2. Évitez de polluer les objets # to_json / # as_json
  3. Évitez d'analyser / de restituer le rendu JSON à l'aide d'un middleware (YUCK!)
  4. Faites-le comme il se doit!

Alors ... remplacez ActionController :: Renderer for JSON! Ajoutez simplement 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

Découvrez awesome_print . Analysez la chaîne JSON dans un Ruby Hash, puis affichez-la 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 ajoutera également une couleur que Stack Overflow ne vous montrera pas:)

Transfert d'un objet ActiveRecord vers JSON (dans la console Rails):

pp User.first.as_json

# => {
 "id" => 1,
 "first_name" => "Polar",
 "last_name" => "Bear"
}

Si vous (comme moi), vous trouvez que l'option pretty_generate intégrée à la bibliothèque JSON de Ruby n'est pas "jolie". assez, je recommande mon propre NeatJSON pour votre mise en forme.

Pour l'utiliser gem installer neatjson puis utiliser JSON.neat_generate au lieu de JSON.pretty_generate .

Comme pour pp de Ruby, il gardera les objets et les tableaux sur une seule ligne quand ils conviendront, mais en superposera 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 prend également en charge diverses options de formatage pour personnaliser davantage votre sortie. Par exemple, combien d'espaces avant / après les deux-points? Avant / après les virgules? Dans les crochets des tableaux et des objets? Voulez-vous trier les clés de votre objet? Voulez-vous que les deux points soient alignés?

Utiliser < pre > , le code HTML et pretty_generate est une bonne astuce:

<%
  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 à partir de cette excellente réponse de @gertas . Cette solution n’est pas spécifique à Rails - elle devrait fonctionner avec n’importe quelle application Rack.

La technique de middleware utilisée ici, à l'aide de #each, est expliquée à l'adresse ASCIIcasts 151: Middleware Rack de Eifion Bedford.

Ce code est placé 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'activer, ajoutez ceci à config / environment / test.rb et à config / environnements / development.rb:

config.middleware.use "PrettyJsonResponse"

Comme @gertas le met en garde dans sa version de cette solution, évitez de l’utiliser en production. C'est un peu lent.

Testé avec Rails 4.1.6.

#At Controller
def branch
    @data = Model.all
    render json: JSON.pretty_generate(@data.as_json)
end

Voici la solution que j'ai tirée d'autres publications au cours de ma propre recherche.

Ceci vous permet d’envoyer les sorties pp et jj dans un fichier si nécessaire.

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é la gemme CodeRay et cela fonctionne plutôt bien. Le format inclut les couleurs et reconnaît de nombreux formats différents.

Je l'ai utilisé sur une gemme qui peut être utilisée pour le débogage des API de rails et cela fonctionne plutôt bien.

À propos, la gemme s'appelle 'api_explorer' ( http://www.github.com/ toptierlabs / api_explorer )

Si vous souhaitez implémenter rapidement cela dans une action du contrôleur Rails 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 lorsque je trouve les en-têtes, l'état et la sortie JSON utiles en tant que un ensemble. La routine d’appel est interrompue sur recommandation d’une présentation Railcast à l’adresse suivante: 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 le 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 lié à 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 corriger ceux de 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

Variante d'impression jolie:

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('=>', ': ')

Résultat:

{"array": [1, 2, 3, {"sample": "hash"}, 44455, 677778, 9900],
 "foo": "bar",
 "rrr": {"pid": 63, "state": false}}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top