Ruby on Rails에서 JSON 출력의 형식을 "예쁘게" 지정하려면 어떻게 해야 하나요?
-
01-07-2019 - |
문제
Ruby on Rails의 JSON 출력이 "예쁘거나" 형식이 좋기를 바랍니다.
지금 당장 전화해 to_json
내 JSON은 모두 한 줄에 있습니다.때때로 JSON 출력 스트림에 문제가 있는지 확인하기 어려울 수 있습니다.
내 JSON을 "예쁘게" 만들거나 Rails에서 보기 좋게 형식화하는 구성 방법이나 방법이 있습니까?
해결책
사용 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"
}
다른 팁
Rack Middleware 및 Rails 3 덕분에 앱 컨트롤러를 변경하지 않고도 모든 요청에 대해 예쁜 JSON을 출력할 수 있습니다.나는 그러한 미들웨어 조각을 작성했으며 브라우저에 JSON이 잘 인쇄되어 있고 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
위의 코드는 다음 위치에 배치되어야 합니다. app/middleware/pretty_json_response.rb
Rails 프로젝트의그리고 마지막 단계는 미들웨어를 등록하는 것입니다. 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에서 테스트됨)
그만큼 <pre>
HTML의 태그, 함께 사용됨 JSON.pretty_generate
, 보기에서 JSON을 보기 좋게 렌더링합니다.나의 저명한 상사가 나에게 다음을 보여주었을 때 나는 매우 기뻤습니다.
<% if @data.present? %>
<pre><%= JSON.pretty_generate(@data) %></pre>
<% end %>
원하는 경우:
- 앱에서 나가는 모든 JSON 응답을 자동으로 예쁘게 만듭니다.
- Object#to_json/#as_json 오염 방지
- 미들웨어를 사용하여 JSON을 구문 분석/재렌더링하지 마세요. (으악!)
- RAILS WAY로 해보세요!
그 다음에 ...JSON용 ActionController::Renderer를 교체하세요!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
확인해 보세요 awesome_print.JSON 문자열을 Ruby Hash로 구문 분석한 후 다음과 같이 awesome_print를 사용하여 표시합니다.
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는 스택 오버플로가 표시하지 않는 색상도 추가합니다 :)
ActiveRecord 객체를 JSON으로 덤프(Rails 콘솔에서):
pp User.first.as_json
# => {
"id" => 1,
"first_name" => "Polar",
"last_name" => "Bear"
}
만약 당신이 (나처럼) 그 사실을 알게 된다면 pretty_generate
Ruby의 JSON 라이브러리에 내장된 옵션은 "예쁘지" 않습니다. 내 옵션을 추천합니다. NeatJSON
서식 지정을 위한 보석입니다.
그것을 사용하려면 gem install neatjson
그런 다음 사용 JSON.neat_generate
대신에 JSON.pretty_generate
.
루비와 마찬가지로 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?"}
]
}
또한 다양한 기능을 지원합니다. 서식 옵션 출력을 추가로 사용자 정의합니다.예를 들어 콜론 앞/뒤에 공백이 몇 개 있습니까?쉼표 앞/뒤?배열과 객체의 괄호 안에 있습니까?개체의 키를 정렬하시겠습니까?콜론을 모두 일렬로 정렬하시겠습니까?
사용 <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>
다음은 다음에서 수정된 미들웨어 솔루션입니다. @gertas의 훌륭한 답변.이 솔루션은 Rails에만 적용되는 솔루션이 아니며 모든 Rack 애플리케이션에서 작동해야 합니다.
여기서 #each를 사용하여 사용된 미들웨어 기술은 다음에서 설명됩니다. ASCIIcast 151:랙 미들웨어 에이피온 베드포드(Eifion Bedford).
이 코드가 들어갑니다 앱/미들웨어/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가 이 솔루션 버전에서 경고한 것처럼 프로덕션 환경에서는 사용하지 마세요.다소 느립니다.
Rails 4.1.6으로 테스트되었습니다.
#At Controller
def branch
@data = Model.all
render json: JSON.pretty_generate(@data.as_json)
end
내 검색 중에 다른 게시물에서 파생된 솔루션은 다음과 같습니다.
이를 통해 필요에 따라 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
나는 보석 CodeRay를 사용했는데 꽤 잘 작동합니다.형식에는 색상이 포함되며 다양한 형식을 인식합니다.
Rails API 디버깅에 사용할 수 있는 gem에서 이를 사용했는데 꽤 잘 작동합니다.
그런데 보석의 이름은 'api_explorer'(http://www.github.com/toptierlabs/api_explorer)
JSON 응답을 보내기 위해 Rails 컨트롤러 작업에서 이를 신속하게 구현하려는 경우:
def index
my_json = '{ "key": "value" }'
render json: JSON.pretty_generate( JSON.parse my_json )
end
헤더, 상태 및 JSON 출력이 세트로 유용한 것을 발견 할 때 다음을 사용합니다.통화 루틴은 다음 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
당신이 사용하는 경우 라블 설명된 대로 구성할 수 있습니다. 여기 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
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
# 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
예쁜 인쇄 변형:
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}}