it-swarm-eu.dev

Jak mohu "pěkně" naformátovat svůj výstup JSON v Ruby na Rails?

Chtěl bych, aby můj výstup JSON v Ruby on Rails byl „hezký“ nebo pěkně naformátovaný.

Právě teď volám to_json a můj JSON je na jedné lince. Někdy to může být obtížné zjistit, zda je problém ve výstupním proudu JSON.

Existuje způsob, jak nakonfigurovat nebo metodu, aby byl můj JSON „hezký“ nebo pěkně naformátovaný v Rails?

578
JP Richardson

Použijte funkci pretty_generate() zabudovanou do novějších verzí JSON. Například:

require 'json'
my_object = { :array => [1, 2, 3, { :sample => "hash"} ], :foo => "bar" }
puts JSON.pretty_generate(my_object)

Což vás dostane:

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

Díky Rack Middleware a Rails 3 můžete vydat pěkný JSON pro každý požadavek, aniž byste změnili jakýkoli ovladač vaší aplikace. Napsal jsem takový middlewarový úryvek a pěkně jsem vytiskl JSON v prohlížeči a 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

Výše uvedený kód by měl být umístěn v app/middleware/pretty_json_response.rb vašeho projektu Rails. A posledním krokem je registrace middlewaru v config/environments/development.rb:

config.middleware.use PrettyJsonResponse

Nedoporučuji jej používat v production.rb. Úprava JSON může snížit dobu odezvy a propustnost vaší produkční aplikace. Nakonec může být zavedena další logika, jako je 'X-Pretty-Json: true', aby se spustilo formátování pro manuální požadavky na zvlnění na vyžádání.

(Testováno s Rails 3.2.8-5.0.0, Ruby 1.9.3-2.2.0, Linux)

70
gertas

Značka <pre> v HTML, která se používá s JSON.pretty_generate, udělá z JSON pěkný pohled. Byl jsem tak šťastný, když mi můj slavný šéf ukázal toto:

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

Pokud chceš:

  1. Automaticky předjeďte všechny odchozí odpovědi JSON z vaší aplikace.
  2. Vyhněte se znečišťování Object # to_json/# as_json
  3. Vyvarujte se analýze/reinterpretaci JSON pomocí middlewaru (YUCK!)
  4. Udělejte to Rails WAY!

Pak ... vyměňte ActionController :: Renderer za JSON! Do aplikace ApplicationController jednoduše přidejte následující kód:

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
20
Ed Lebert

Podívejte se super_print . Analyzujte řetězec JSON na Ruby Hash a poté jej zobrazte s úžasným potiskem takto:

require "awesome_print"
require "json"

json = '{"holy": ["nested", "json"], "batman!": {"a": 1, "b": 2}}'

ap(JSON.parse(json))

S výše uvedeným uvidíte:

{
  "holy" => [
    [0] "nested",
    [1] "json"
  ],
  "batman!" => {
    "a" => 1,
    "b" => 2
  }
}

awesome_print také přidá nějakou barvu, kterou vám Stack Overflow neukáže :)

11
Synthead

Použití kódu <pre> html a pretty_generate je dobrý trik:

<%
  require 'json'

  hash = JSON[{hey: "test", num: [{one: 1, two: 2, threes: [{three: 3, tthree: 33}]}]}.to_json] 
%>

<pre>
  <%=  JSON.pretty_generate(hash) %>
</pre>
10
oj5th

Výpis objektu ActiveRecord do JSON (v konzole Rails):

pp User.first.as_json

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

Pokud (jako já) zjistíte, že volba pretty_generate vestavěná do knihovny JSON v Ruby není dost "hezká", doporučuji pro formátování svůj vlastní NeatJSONNAME _ drahokam.

Chcete-li jej použít gem install neatjson a poté použít JSON.neat_generate místo JSON.pretty_generate.

Stejně jako Ruby je ppname__, bude udržovat objekty a pole na jednom řádku, když se vejdou, ale podle potřeby se zabalí do více. Například:

{
  "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?"}
  ]
}

Podporuje také řadu možnosti formátování pro další přizpůsobení vašeho výstupu. Například kolik mezer před/po dvojtečkách? Před/po čárkách? Uvnitř závorek polí a předmětů? Chcete třídit klíče svého objektu? Chcete, aby byly všechny dvojtečky uspořádány?

10
Phrogz

Zde je řešení middleware upravené z tato vynikající odpověď @ gertas . Toto řešení není specifické pro Rails - mělo by fungovat s jakoukoli aplikací Rack.

Technika middleware použitá zde pomocí #each je vysvětlena v ASCIIcasts 151: Rack Middleware Eifion Bedford.

Tento kód jde do aplikace/middlewaru/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

Chcete-li jej zapnout, přidejte toto do config/environment/test.rb a config/environment/development.rb:

config.middleware.use "PrettyJsonResponse"

Jak @ gertas varuje ve své verzi tohoto řešení, nepoužívejte jej ve výrobě. Je to poněkud pomalé.

Testováno s Rails 4.1.6.

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

Použil jsem klenot CodeRay a funguje to docela dobře. Formát zahrnuje barvy a rozpoznává mnoho různých formátů.

Použil jsem ji na drahokam, který lze použít pro ladění Rails API a funguje to docela dobře.

Mimochodem, klenot je pojmenován 'api_Explorer' ( http://www.github.com/toptierlabs/api_Explorer )

2
Tony

Pokud to chcete rychle implementovat do akce řadiče Rails a odeslat odpověď JSON:

def index
  my_json = '{ "key": "value" }'
  render json: JSON.pretty_generate( JSON.parse my_json )
end
2
sealocal

Zde je moje řešení, které jsem odvodil z jiných příspěvků během vlastního vyhledávání.

To vám umožní odeslat výstup pp a jj do souboru podle potřeby.

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
2

Používám následující, protože považuji záhlaví, stav a výstup JSON za užitečnou jako sadu. Rutina volání je rozdělena na doporučení z prezentace Railscasts na adrese: 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
1
TheDadman

Pokud používáte RABL , můžete jej nakonfigurovat tak, jak je popsáno zde pro použití 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

Problém s použitím JSON.pretty_generate je v tom, že validátoři schématu JSON již nebudou spokojeni s vašimi řetězci datetime. Ty ve svém config/initializers/rabl_config.rb můžete opravit pomocí:

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
1
Jim Flood

# example of use:
a_hash = {user_info: {type: "query_service", e_mail: "[email protected]", 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
1
Sergio Belevskij

Docela tisková varianta:

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

Výsledek:

{"array": [1, 2, 3, {"sample": "hash"}, 44455, 677778, 9900],
 "foo": "bar",
 "rrr": {"pid": 63, "state": false}}
0
SergA