it-swarm-id.com

Bagaimana saya bisa "cantik" memformat output JSON saya di Ruby on Rails?

Saya ingin output JSON saya di Ruby on Rails menjadi "cantik" atau diformat dengan baik.

Saat ini, saya memanggil to_json dan JSON saya semuanya dalam satu baris. Kadang-kadang ini bisa sulit untuk melihat apakah ada masalah dalam aliran output JSON.

Apakah ada cara untuk mengkonfigurasi atau metode untuk membuat JSON saya "cantik" atau diformat dengan baik di Rails?

578
JP Richardson

Gunakan fungsi pretty_generate(), yang dibangun ke dalam versi JSON yang lebih baru. Sebagai contoh:

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

Yang membuat Anda:

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

Berkat Rack Middleware dan Rails 3 Anda dapat menampilkan JSON cantik untuk setiap permintaan tanpa mengubah pengontrol aplikasi Anda. Saya telah menulis potongan middleware tersebut dan saya mendapatkan JSON yang tercetak dengan baik di browser dan output 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

Kode di atas harus ditempatkan di app/middleware/pretty_json_response.rb proyek Rails Anda. Dan langkah terakhir adalah mendaftarkan middleware di config/environments/development.rb:

config.middleware.use PrettyJsonResponse

Saya tidak menyarankan untuk menggunakannya di production.rb. Pemrosesan ulang JSON dapat menurunkan waktu respons dan throughput aplikasi produksi Anda. Akhirnya, logika tambahan seperti tajuk 'X-Pretty-Json: true' dapat diperkenalkan untuk memicu pemformatan untuk permintaan ikal manual sesuai permintaan.

(Diuji dengan Rails 3.2.8-5.0.0, Ruby 1.9.3-2.2.0, Linux)

70
gertas

Tag <pre> dalam HTML, digunakan dengan JSON.pretty_generate, akan membuat JSON cantik di tampilan Anda. Saya sangat senang ketika bos terkenal saya menunjukkan ini kepada saya:

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

Jika Anda menghendaki:

  1. Prettify semua respons JSON keluar dari aplikasi Anda secara otomatis.
  2. Hindari mencemari Objek # to_json/# as_json
  3. Hindari parsing/rendering ulang JSON menggunakan middleware (YUCK!)
  4. Lakukan Rails WAY!

Lalu ... ganti ActionController :: Renderer untuk JSON! Cukup tambahkan kode berikut ke ApplicationController Anda:

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

Lihat awesome_print . Parsing string JSON ke Ruby Hash, lalu tampilkan dengan awesome_print seperti:

require "awesome_print"
require "json"

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

ap(JSON.parse(json))

Dengan yang di atas, Anda akan melihat:

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

awesome_print juga akan menambahkan beberapa warna yang tidak akan ditampilkan oleh Stack Overflow :)

11
Synthead

Menggunakan <pre> kode html dan pretty_generate adalah trik yang bagus:

<%
  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

Membuang objek ActiveRecord ke JSON (di konsol Rails):

pp User.first.as_json

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

Jika Anda (seperti saya) menemukan bahwa opsi pretty_generate yang dibangun di perpustakaan JSON Ruby tidak cukup "cantik", saya sarankan permata saya sendiri NeatJSON untuk pemformatan Anda.

Untuk menggunakannya gem install neatjson dan kemudian gunakan JSON.neat_generate alih-alih JSON.pretty_generate.

Seperti Ruby pp, Ruby akan menyimpan objek dan array pada satu baris saat cocok, tetapi bungkus menjadi beberapa sesuai kebutuhan. Sebagai contoh:

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

Ini juga mendukung berbagai opsi pemformatan untuk lebih lanjut menyesuaikan output Anda. Misalnya, berapa banyak spasi sebelum/sesudah titik dua? Sebelum/sesudah koma? Di dalam kurung array dan benda? Apakah Anda ingin menyortir kunci objek Anda? Apakah Anda ingin semua titik dua berbaris?

10
Phrogz

Ini adalah solusi middleware yang dimodifikasi dari jawaban yang sangat bagus ini oleh @gertas . Solusi ini tidak spesifik untuk Rails - ini harus bekerja dengan aplikasi Rack apa pun.

Teknik middleware yang digunakan di sini, menggunakan #each, dijelaskan di ASCIIcasts 151: Rack Middleware oleh Eifion Bedford.

Kode ini masuk 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

Untuk mengaktifkannya, tambahkan ini ke config/environment/test.rb dan config/environment/development.rb:

config.middleware.use "PrettyJsonResponse"

Ketika @gertas memperingatkan dalam versinya tentang solusi ini, hindari menggunakannya dalam produksi. Agak lambat.

Diuji dengan Rails 4.1.6.

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

Saya telah menggunakan permata CodeRay dan itu bekerja dengan sangat baik. Formatnya termasuk warna dan mengenali banyak format yang berbeda.

Saya telah menggunakannya pada permata yang dapat digunakan untuk debugging Rails APIs dan berfungsi dengan baik.

Omong-omong, permata itu bernama 'api_Explorer' ( http://www.github.com/toptierlabs/api_Explorer )

2
Tony

Jika Anda ingin menerapkan ini dengan cepat dalam tindakan pengontrol Rails untuk mengirim respons JSON:

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

Inilah solusi saya yang saya dapatkan dari posting lain selama pencarian saya sendiri.

Ini memungkinkan Anda untuk mengirim output pp dan jj ke file sesuai kebutuhan.

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

Saya menggunakan berikut ini karena saya menemukan header, status dan output JSON berguna sebagai satu set. Rutinitas panggilan dipecah berdasarkan rekomendasi dari presentasi railscast di: 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

Jika Anda menggunakan RABL Anda dapat mengkonfigurasinya seperti yang dijelaskan di sini untuk menggunakan 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

Masalah dengan menggunakan JSON.pretty_generate adalah bahwa validator skema JSON tidak akan lagi senang dengan string datetime Anda. Anda dapat memperbaikinya di config/initializers/rabl_config.rb Anda dengan:

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

Varian cetak cantik:

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

Hasil:

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