我如何“漂亮”格式化我的JSON输出在Ruby on Rails的?
我想我的JSON在Ruby on Rails的输出是“漂亮”或很好的格式。
现在,我打电话给to_json
和我的JSON都在一行。 有时候,如果JSON输出stream中存在问题,可能很难查看。
有没有办法configuration或使我的JSON“漂亮”或良好的格式在Rails中的方法?
使用内置于更高版本的JSON中的pretty_generate()
函数。 例如:
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,而不需要改变你的应用程序的任何控制器。 我已经编写了这样的中间件代码片段,并在浏览器和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
上面的代码应该放在你的Rails项目的app/middleware/pretty_json_response.rb
中。 最后一步是在config/environments/development.rb
注册中间件:
config.middleware.use PrettyJsonResponse
我不build议在production.rb
使用它 。 JSONparsing可能会降低生产应用程序的响应时间和吞吐量。 最终额外的逻辑,例如'X-Pretty-Json:true'头部可以被引入以触发手动curl请求的格式化。
(使用Rails 3.2.8-5.0.0,Ruby 1.9.3-2.2.0,Linuxtesting)
HTML中的<pre>
标记与JSON.pretty_generate
一起JSON.pretty_generate
,将在您的视图中呈现JSON。 当我的杰出老板向我展示这件事时,我感到非常高兴:
<% if !@data.blank? %> <pre><%= JSON.pretty_generate(@data) %></pre> <% end %>
如果你想:
- 从您的应用程序自动美化所有传出的JSON响应。
- 避免污染Object#to_json /#as_json
- 避免使用中间件parsing/重新渲染JSON(YUCK!)
- 做它的方式!
然后…replaceJSON的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
将ActiveRecord对象转储到JSON(在Rails控制台中):
pp User.first.as_json # => { "id" => 1, "first_name" => "Polar", "last_name" => "Bear" }
退房awesome_print 。 将JSONstringparsing为一个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也将添加一些颜色,堆栈溢出不会显示你:)
如果你(像我)发现Ruby的JSON库中内置的pretty_generate
选项不够“漂亮”,我推荐自己的NeatJSON
gem来进行格式化。
要使用它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?"} ] }
它还支持各种格式化选项,以进一步自定义您的输出。 例如,冒号前/后有多less个空格? 之前/之后的逗号? 在数组和对象的括号内? 你想sorting你的对象的键? 你想冒号排成一行吗?
这里是一个中间件解决scheme, 由@gertas这个优秀的答案修改 。 这个解决scheme不是Rails特有的,它应该适用于任何Rack应用程序。
这里使用的中间件技术使用#each,在Eifion Bedford的ASCIIcasts 151:Rack Middleware中有解释。
这段代码进入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在他的解决scheme中警告的,避免在生产中使用它。 这有点慢。
经过Rails 4.1.6testing。
这是我在自己的search过程中从其他post中获得的解决scheme。
这使您可以根据需要将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
我已经使用了gemCodeRay,它工作得很好。 格式包括颜色,它可以识别很多不同的格式。
我已经在一个可用于debuggingrails API的gem上使用它,它工作得很好。
顺便说一句,这个gem被命名为“api_explorer”( http://www.github.com/toptierlabs/api_explorer )
如果你正在寻找在Rails控制器动作中快速实现这个动作来发送JSON响应:
def index my_json = '{ "key": "value" }' render json: JSON.pretty_generate( JSON.parse my_json ) end
使用<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>
我使用以下,因为我发现标题,状态和JSON输出有用作为一个集合。 调用例程按照以下url上的railscast演示推荐: 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
如果你正在使用RABL,你可以像这里描述的那样configuration它来使用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模式validation器将不再满足于您的date时间string。 你可以在你的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
# 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
# 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
#At Controller def branch @data = Model.all render json: JSON.pretty_generate(@data.as_json) end