在我的rails 3.2 app中,我正在使用jbuilder来呈现来自我的JSON api的响应。
我想为所有API响应提供一个通用结构,布局可能是让我的视图保持干净的可能解决方案。
ex:我希望每个回复都是以下形式:
{
status: "ok|error|redirect",
data: { ... JSON specific to the current view ... },
errors: [ ... ],
notes: [ ... ]
}
(数据的值是视图提供的json结构,其他一切都来自布局)
然而:我无法正确地让jbuilder布局屈服于视图。
# in layout
json.data yield
# in view
json.some "value"
结果:
{"data":"{\"some\":\"value\"}"} # arg! my json has become a string
以另一种方式尝试:
# in layout
yield
# in view
json.data do |json|
json.some "value"
end
结果:
{}
有没有人用jbuilder或其他json模板gem /方法做到这一点?
这juilder github issue表明这是可能的,但表明其他人也有类似的问题。
我看到rabl(https://github.com/nesquena/rabl/)应该支持布局(https://github.com/nesquena/rabl/wiki/Using-Layouts),但我已经决定了不要因为其他原因而使用它(rabl使复杂的json结构成为一场噩梦,尤其是在试图控制对象根等时)。
答案 0 :(得分:11)
我会根据我们提出的解决方案为您提供替代方案:
# app/helpers/application_helper.rb
module ApplicationHelper
def envelope(json, status, errors, notes)
json.status status
json.data do
yield if block_given?
end
json.errors errors
json.notes notes
end
end
然后,在视图中,您可以调用信封并包含您的json代码,如:
# app/views/api/v1/test/show.json.jbuilder
envelope(json, "OK" ) do
json.some 'value'
end
答案 1 :(得分:10)
你可以这样做
# api.v1.json.jbuilder - layout
json.request do
json.message "your message"
json.status 200
end
json.data JSON.parse(yield)
# show.json.jbuilder - action view
json.name 'Some item name'
答案 2 :(得分:5)
迟到的答案,但帮助我得到了我想要的东西......
成功结果:
{ "something": {"id": 42, "message": "hello"}, "status": "ok", "errors": [] }
错误结果:
{ "something": null, "status": "error", "errors": ["could not do the thing"] }
代码:
应用/控制器/ API / V1 / base_controller.rb 强>
class Api::V1::BaseController < ActionController::API
layout 'api/v1/application'
before_action :setup_layout_elements
def setup_layout_elements
@status = :ok
@errors = []
end
def error!(message)
@status = :error
@errors << message
nil
end
end
应用/控制器/ API / V1 / some_controller.rb 强>
class Api::V1::SomeController < Api::V1::BaseController
def index
@something = begin
possibly_error_causing_code
rescue
error!('could not do the thing')
end
render builder: 'api/v1/something/index'
end
end
应用/视图/布局/ API / V1 / application.json.jbuilder 强>
json.merge! JSON.parse(yield)
json.status @status
json.errors @errors
应用/视图/ API / V1 /东西/ index.json.jbuilder 强>
json.something do
json.id @something.id
json.message @something.to_s
end
答案 3 :(得分:2)
答案 4 :(得分:1)
如果您不想加入额外的密钥,可以这样做
class UsersController < ApplicationController
layout: 'json_layout'
end
在/app/views/layouts/json_layout.json.jbuilder
json.success true
r = JSON.parse(yield)
r.each{|k,v|
json.set! k,v
}
答案 5 :(得分:1)
JBuilder不支持使用json.jbuilder
作为您的布局(请参阅Github上的问题#172)。
我设法避免使用parse
作为我的布局格式,进行额外一轮generate
&amp; json.erb
。
应用程序/控制器/ API / base_controller.rb:
class Api::BaseController < ActionController::Base
layout "api.v1"
end
应用程序/视图/布局/ api.v1.json.erb:
{
<% if @api_errors.present? %>
"errors": <%= raw JSON.dump @api_errors %>,
<% else %>
"data": <%= yield %>,
<% end %>
"meta": <%= raw JSON.dump @api_meta %>
}
答案 6 :(得分:0)
jbuilder是一种非常简单的API视图技术,你可以在这里添加部分内容,所以如果你想为所有API创建一个装饰器或为公共响应创建部分响应,并在需要时调用该响应
让我们说如果你想要
{
status: "ok|error|redirect",
data: { ... JSON specific to the current view ... },
errors: [ ... ],
notes: [ ... ]
}
为此创建一个部分 /视图/ API /普通/ _some_partial
json.status "ok whatever the message"
json.data do
json.message "message"
end
json.errors @errors
json.notes @notes_array
它为您的问题提供了非常简单的解决方案。
干杯