Rails JSON API макеты с Jbuilder (или другие)
в моем приложении rails 3.2 я использую на JBuilder для отображения ответов из моего api JSON.
Я хочу предоставить общую структуру для всех ответов API, и макет будет вероятным решением, чтобы сохранить мои представления сухими.
ex: я хотел бы, чтобы каждый ответ был следующего вида:
{
status: "ok|error|redirect",
data: { ... JSON specific to the current view ... },
errors: [ ... ],
notes: [ ... ]
}
(где значение сведения является структурой json, предоставляемой видом, все остальное - из макета)
Однако: I не удается получить макет 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 templating gem/method?
этой вопрос juilder на GitHub предполагает, что это возможно, но указывает, что у других есть аналогичные проблемы.
Я вижу рабль (https://github.com/nesquena/rabl/) должен поддерживать макеты (https://github.com/nesquena/rabl/wiki/Using-Layouts), но я решил не использовать его по другим причинам (rabl делает сложные структуры json кошмаром, особенно при попытке контролировать корни объектов и т. д.).
7 ответов
вы можете сделать это таким образом
# 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'
Я дам вам альтернативу, основанную на решении, которое мы придумали:
# 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
поздний ответ, но помог мне сделать то, что я искал...
Успех Результат:
{ "something": {"id": 42, "message": "hello"}, "status": "ok", "errors": [] }
ошибка Результат:
{ "something": null, "status": "error", "errors": ["could not do the thing"] }
код:
app / контроллеры / 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
app / контроллеры / 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
app / views / layouts / api / v1 / application.формат JSON.на JBuilder
json.merge! JSON.parse(yield)
json.status @status
json.errors @errors
app / views / api/v1/что-то / индекс.формат JSON.на JBuilder
json.something do
json.id @something.id
json.message @something.to_s
end
попробовать
json.merge! JSON.parse(yield)
https://github.com/rails/jbuilder/issues/8#issuecomment-27586784
Если вы не хотите включать дополнительный ключ, вы можете сделать это
class UsersController < ApplicationController
layout: 'json_layout'
end
In/app/views/layouts / json_layout.формат JSON.на JBuilder
json.success true
r = JSON.parse(yield)
r.each{|k,v|
json.set! k,v
}
JBuilder не поддерживает использование json.jbuilder
как ваш макет (см. вопрос #172 на Github).
мне удалось избежать дополнительного раунда parse
&generate
С помощью json.erb
как мой формат.
app / контроллеры / api / base_controller.rb:
class Api::BaseController < ActionController::Base
layout "api.v1"
end
app / views / макеты / api.В1.формат JSON.Эрб:
{
<% if @api_errors.present? %>
"errors": <%= raw JSON.dump @api_errors %>,
<% else %>
"data": <%= yield %>,
<% end %>
"meta": <%= raw JSON.dump @api_meta %>
}
jbuilder-довольно простая техника для представлений API здесь вы можете добавить частичные, поэтому, если вы хотите один и тот же ответ для всего API, создайте декоратор или создайте частичный для общего ответа и вызовите этот ответ, когда вам это нужно
давайте скажем, если вы хотите
{
status: "ok|error|redirect",
data: { ... JSON specific to the current view ... },
errors: [ ... ],
notes: [ ... ]
}
создайте частичное для этого / views / api / common / _some_partial
json.status "ok whatever the message"
json.data do
json.message "message"
end
json.errors @errors
json.notes @notes_array
ее довольно простое решение для вашего вопроса.
Ура