2012-07-17 55 views
9

在我的rails 3.2应用程序中,我使用jbuilder来呈现来自我的JSON API的响应。使用Jbuilder(或其他)的Rails JSON API布局

我想为所有API响应提供一个通用结构,并且布局可能是保持视图干爽的可能解决方案。

)(我想每个响应是以下形式的:

{ 
    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模板宝石/方法?

juilder github issue暗示这是可能的,但表明其他人有类似的问题。

我看到rabl(https://github.com/nesquena/rabl/)应该支持布局(https://github.com/nesquena/rabl/wiki/Using-Layouts),但我已经因为其他原因决定不使用它(rabl使复杂的json结构成为一场噩梦,特别是在试图控制对象根等时)。

回答

9

您可以通过这种方式做到这一点

# 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' 
+0

我喜欢你的这个打算但似乎有点浪费,解析JSON只是吐了一口气直接回来了 – 2014-06-09 18:31:02

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 
+0

你''做''信封(json,“确定”)''在视图代码 – JVK 2013-08-13 06:22:45

+0

任何想法关于http://stackoverflow.com/questions/18202750/rails4-jbuilder-always-return-status-code-200-even-if-i-put-other-status-code – JVK 2013-08-13 07:19:21

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

晚的答案,但让我明白我是寻找...

成功结果:

{ "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/something/index.json.jbuilder

json.something do 
    json.id  @something.id 
    json.message @something.to_s 
end 
+0

伟大的解决方案,正是我所期待的。谢谢。 – 2015-12-03 21:53:26

+0

你将如何设置http响应代码? – trigun0x2 2016-10-27 23:26:21

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 

它非常简单的解决方案。

干杯

1

JBuilder中不支持使用json.jbuilder为您的布局(见Github上的问题#172)。

我设法避免做一个额外的一轮parse & generate通过使用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 %> 
}