10

Rails 3.2 アプリでは、JSON API からの応答をレンダリングするためにjbuilderを使用しています。

すべての API 応答に共通の構造を提供したいと考えており、ビューを DRY に保つためのソリューションとしてレイアウトが適しています。

例: すべての応答を次の形式にしたい:

{
  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/methodでこれを成功させた人はいますか?

このjuilder github issueは可能性を示唆していますが、他の人にも同様の問題があることを示しています。

rabl (https://github.com/nesquena/rabl/) はレイアウト (https://github.com/nesquena/rabl/wiki/Using-Layouts) をサポートするはずですが、使用しないことにしましたそれは他の理由によるものです (rabl は、複雑な json 構造を悪夢にします。特に、オブジェクトのルートを制御しようとする場合など)。

4

7 に答える 7

14

私たちが思いついた解決策に基づいて、代替案を提供します。

# 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
于 2012-10-11T04:14:53.673 に答える
11

この方法でこれを行うことができます

# 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'
于 2012-09-24T12:25:44.890 に答える
9

遅い答えですが、探していたものを手に入れるのに役立ちました...

成功結果:

{ "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
于 2014-10-15T16:13:46.983 に答える
2

試す

 json.merge! JSON.parse(yield)

https://github.com/rails/jbuilder/issues/8#issuecomment-27586784

于 2014-08-11T08:42:12.097 に答える
2

json.jbuilderJBuilder は、レイアウトとしての使用をサポートしていません( Github の問題#172を参照)。

レイアウト形式として使用することで、 parse&の余分なラウンドを回避することができました。generatejson.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 %>
}
于 2016-05-27T14:06:29.667 に答える