Ruby on Rails에서 JSON 출력을“예쁜”형식으로 만드는 방법


626

Ruby on Rails의 JSON 출력을 "예쁜"형식으로 바꾸고 싶습니다.

지금은 전화 to_json 하고 JSON은 모두 한 줄에 있습니다. 때때로 이것은 JSON 출력 스트림에 문제가 있는지 확인하기 어려울 수 있습니다.

내 JSON을 "예쁜"형식으로 만들거나 Rails에서 멋진 형식으로 구성 할 수있는 방법이 있습니까?


2
어디를보고 있는지 확실하지 않지만 webkit의 콘솔에서는 로깅되거나 요청 된 모든 JSON에서 멋진 트리를 만듭니다.
Ryan Florence

8
이 작업을 수행 할 때 기억해야 할 한 가지는 추가 공백으로 인해 JSON 컨텐츠의 크기가 커진다는 것입니다. 개발 환경에서는 JSON을 쉽게 읽을 수 있도록하는 것이 종종 도움이되지만 프로덕션 환경에서는 사용자 브라우저에서 속도와 응답 성을 확보 할 수있을 정도로 콘텐츠를 간결하게 만들고 싶습니다.
Tin Man

2
y my_json빠른 수정을 원할 경우 사용 하면 멋지게 서식이 지정됩니다.
randomor

5
@randomorundefined method 'y' for main:Object
nurettin

y레일 콘솔에서 사용할 수 있습니다.
Sophia Feng

답변:


999

pretty_generate()이후 버전의 JSON에 내장 된 함수를 사용하십시오 . 예를 들면 다음과 같습니다.

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

당신을 얻는다 :

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

32
맵시 있는! 나는 이것을 ~ / .irbrc에 넣었다. def json_pp (json)은 JSON을 넣는다. pretty_generate (JSON.parse (json)) end
TheDeadSerious

10
레일이 유용하려면, 당신은 같은 맥락에서 사용할 수있는 코드가 포함 된 답변을 제공해야한다는 것format.json { render :json => @whatever }
우상 파괴자

9
확실하게 prettyprinting은 서버 측 디버깅에만 사용해야합니까? 위의 코드를 컨트롤러에 붙이면 모든 응답에 쓸모없는 공백이 생길 것입니다. 소프 (예 : Firebug)의 가치가있는 도구가 이미 예쁜 인쇄 JSON을 처리하므로 클라이언트 측 디버깅에는 필요하지 않습니다.
lambshaanxy

8
@ jpatokal : 다른 더 나은 옵션이 있다고 생각할 수도 있지만, Rails에서 작동시키는 방법에 대한 질문이었습니다. "Rails에서하고 싶지 않다"고 말하는 것은 대답이 아닙니다. 분명히 많은 사람들이 Rails에서하고 싶어합니다.
iconoclast

39
오리지널 포스터는 Rails 앱에서 어디 에서 이것을 사용하고 싶은지에 대해 아무 것도 말하지 않았 으므로 어디에서나 작동하는 Ruby 라인으로 대답했습니다. 이를 사용하여 Rails 컨트롤러 에서 JSON 응답을 생성하려면 이미 자신의 질문에 대답했습니다 format.json { render :json => JSON.pretty_generate(my_json) }.
lambshaanxy

78

Rack Middleware 및 Rails 3 덕분에 앱의 컨트롤러를 변경하지 않고도 모든 요청에 ​​대해 예쁜 JSON을 출력 할 수 있습니다. 나는 그러한 미들웨어 스 니펫을 작성했으며 브라우저와 curl출력 에서 JSON을 멋지게 인쇄했습니다 .

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

위의 코드는 app/middleware/pretty_json_response.rbRails 프로젝트에 배치해야합니다 . 마지막 단계는 미들웨어를 config/environments/development.rb다음에 등록하는 것입니다 .

config.middleware.use PrettyJsonResponse

나는 그것을 사용하지 않는 것이 좋습니다 production.rb . JSON 재분석은 프로덕션 앱의 응답 시간 및 처리량을 저하시킬 수 있습니다. 결국 'X-Pretty-Json : true'헤더와 같은 추가 로직이 도입되어 요청시 수동 컬 요청의 서식을 트리거 할 수 있습니다.

(Rails 3.2.8-5.0.0, Ruby 1.9.3-2.2.0, Linux로 테스트)


2
ActiveSupport의 to_json 재정의 를 어떻게 해결하고 있습니까? ActiveSupport가있는 동안 인쇄가 잘되지 않습니다.
Ammo Goettsch

1
나는 주로 사용하는 to_json, as_json, jbuilder 를 신경 쓰지 않습니다 . 미들웨어는 JSON 출력을 변환합니다. 가능할 때마다 수업을 여는 것을 피하려고 노력합니다.
gertas

1
구문 분석 줄을 변경하여 obj = JSON.parse(response.body.first)작동시켜야했습니다.
Kimmo Lehto

5
Rails 4에서도 잘 작동합니다. 감사합니다! 나는 이것을 더 도서관 고유의 방법보다 선호합니다 (허용 된 답변 에서처럼). 어쨌든 dev 모드에서만 이것을 사용해야하기 때문에 성능 적중은 그리 크지 않습니다.
elsurudo

3
Rails 5에서는로 변경 Rack::Utils.bytesize(pretty_str).to_s해야 pretty_str.bytesize.to_s했고 훌륭하게 작동했습니다!
panteo

77

<pre>와 함께 사용되는 HTML 의 태그 JSON.pretty_generate는 JSON을보기에 아름답게 렌더링합니다. 저의 유명한 상사가 나에게 이것을 보여 주었을 때 너무 기뻤습니다.

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

5
깨끗하고 간결합니다!
Sean Szurko 2012 년

23

원하는 경우 :

  1. 앱에서 나가는 모든 JSON 응답을 자동으로 확인합니다.
  2. Object # to_json / # as_json을 오염시키지 마십시오
  3. 미들웨어 (YUCK!)를 사용하여 JSON 구문 분석 / 다시 렌더링하지 마십시오
  4. 그것을 레일 방식으로하십시오!

그런 다음 ... ActionController :: Renderer for JSON! 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

이 굉장하지만 실제로 날짜 / 시간이 다르게 렌더링됩니다 : gist.github.com/nornagon/9c24b68bd6d3e871add3을
nornagon

이것에 대한 몇 가지 문제 : (1) JSON.pretty_generate에는 json.respond_to?(:to_h)또는이 필요합니다 :to_hash. (2) pretty_generate는 to_json 이하 지 않는 것들을 질식시킬 수 있습니다.
Christopher Oezbek 5

@nornagon 나는이 변경 사항을 적용하지 않았으며 .to_json과 pretty_generate와 같은 차이점을 얻었습니다. 나는 일반 콘솔이 아닌 레일 콘솔에서만 볼 수 있습니다. 나는 이것이 일반적인 레일 일 수 있다고 생각합니다.이 패치와 관련이 없습니다. 또한 Time.parse는 두 형식 모두에서 문자열을 시간으로 다시 변환 할 때 동일한 결과를 반환합니다. 타임 스탬프에 대한 로그를 검색 할 때 약간의 불편 함이 있지만 어쨌든 약간의 \ s +를 추가하는 것이 실제로 큰 문제는 아닙니다.
con--

문제 같은 외모 @nornagon 당신 톱 ActiveSupport의이었다 재정 에 언급 한 바와 같이, to_json의 탄약 Goettsch의 코멘트
con--

17

멋진 인쇄를 확인하십시오 . JSON 문자열을 Ruby Hash로 구문 분석 한 후 다음과 ap같이 표시하십시오 .

require "awesome_print"
require "json"

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

ap(JSON.parse(json))

위와 같이 표시됩니다.

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

Awesome Print는 또한 Stack Overflow에 표시되지 않는 색상을 추가합니다.


2
당신과 동의! awesome_print는 간단합니다!
Aashish

2
우리는 프로젝트에도 awesome_print를 사용하고 있으며 이름은-> awesome
Simon Franzen

13

Rails 콘솔에서 ActiveRecord 객체를 JSON으로 덤프 :

pp User.first.as_json

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

3
pp인쇄 대신 표준 출력 으로 문자열을 가져 오려면을 사용하십시오 User.first.as_json.pretty_inspect. 나를 위해 잘 작동합니다.
Johnny Wong

12

<pre>HTML 코드를 사용 하고 pretty_generate좋은 트릭입니다.

<%
  require 'json'

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

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

12

당신이 찾아내는 경우 pretty_generate루비의 JSON 라이브러리에 내장 된 옵션은 "꽤"충분하지 않다, 나는 내 자신의 추천 NeatJSON을 당신의 서식에 대한 보석을.

그것을 사용하려면 :

gem install neatjson

그런 다음 사용

JSON.neat_generate

대신에

JSON.pretty_generate

Ruby와 마찬가지로 pp객체와 배열은 적합 할 때 한 줄에 유지하지만 필요에 따라 여러 줄로 줄 바꿈합니다. 예를 들면 다음과 같습니다.

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

또한 출력을 추가로 사용자 정의하기 위해 다양한 형식화 옵션 을 지원합니다 . 예를 들어, 콜론 전후에 몇 개의 공백이 있습니까? 쉼표 전후? 배열과 객체의 괄호 안에? 객체의 키를 정렬 하시겠습니까? 콜론을 모두 정렬 하시겠습니까?


2
이 보석은 바위-결장에 정렬이 특히 달콤합니다!
webdevguy

8

다음은 @gertas의 훌륭한 답변 에서 수정 된 미들웨어 솔루션 입니다. 이 솔루션은 Rails 전용이 아니며 모든 랙 응용 프로그램에서 작동해야합니다.

여기서 #each를 사용하는 미들웨어 기술은 ASCIIcasts 151 : Eifion Bedford의 랙 미들웨어 에 설명되어 있습니다.

이 코드는 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

켜려면 config / environments / test.rb 및 config / environments / development.rb에 추가하십시오.

config.middleware.use "PrettyJsonResponse"

@gertas는이 솔루션의 버전에서 경고하므로 프로덕션 환경에서는 사용하지 마십시오. 다소 느립니다.

레일 테스트 4.1.6.



4

내 검색 중 다른 게시물에서 파생 된 솔루션이 있습니다.

이를 통해 필요에 따라 pp 및 jj 출력을 파일로 보낼 수 있습니다.

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

3

gemCodeRay를 사용했는데 꽤 잘 작동합니다. 형식에는 색상이 포함되며 다양한 형식을 인식합니다.

레일 API 디버깅에 사용할 수있는 gem에 사용했으며 꽤 잘 작동합니다.

그런데 보석의 이름은 'api_explorer'( http://www.github.com/toptierlabs/api_explorer )입니다.


3

JSON 응답을 전송하기 위해 Rails 컨트롤러 작업에서이를 빠르게 구현하려는 경우 :

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

2

RABL 을 사용하는 경우 여기 에 설명 된대로 JSON을 사용하도록 RABL을 구성 할 수 있습니다 .

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

JSON.pretty_generate를 사용할 때의 문제점은 JSON 스키마 유효성 검사기가 더 이상 날짜 시간 문자열에 만족하지 않는다는 것입니다. config / initializers / rabl_config.rb에서 다음을 사용하여 수정할 수 있습니다.

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

2

# 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

1

헤더, 상태 및 JSON 출력이 세트로 유용하다는 것을 알기 때문에 다음을 사용합니다. 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

예쁜 인쇄 변형 :

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

결과:

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

0

가장 간단한 예는 다음과 같습니다.

my_json = '{ "name":"John", "age":30, "car":null }'
puts JSON.pretty_generate(JSON.parse(my_json))

레일즈 콘솔 예 :

core dev 1555:0> my_json = '{ "name":"John", "age":30, "car":null }'
=> "{ \"name\":\"John\", \"age\":30, \"car\":null }"
core dev 1556:0> puts JSON.pretty_generate(JSON.parse(my_json))
{
  "name": "John",
  "age": 30,
  "car": null
}
=> nil
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.