Skip to content
mikeweber edited this page Jan 17, 2013 · 8 revisions

Using Layouts in RABL

It may be desirable to use a common layout file for all JSON responses to include a response code or other metadata. For example, the Google Geocoder API returns a status field, and all response data under results.

When returning JSON data, the rails application will merge controller output with a layout file via yield, just as can be done with view layout files. Below is an example json layout file.

Note: We use the Yajl (yajl-ruby) binding in the examples below, but choose any JSON parser you like.

Creating a JSON response

Using Erb

Filename: app/views/layouts/application.json.erb

You can do this two (or even more) different ways:

{
  "metadata": <%= @metadata.to_json.html_safe %>,
  "error": <%= @error.to_json.html_safe %>,
  "result": <%= yield %>
}
<%=
  raw({
    metadata: @metadata,
    error: @error,
    result: Yajl::Parser.parse(yield)
  }.to_json)
%>

Using Haml

Filename: app/views/layouts/application.json.haml

Add haml to the Gemfile:

gem 'haml'
:plain
  {
    "status": #{response.status},
    "error": #{@error.to_json.html_safe},
    "result": #{yield}
  }

Using JsonBuilder

Filename: app/views/layouts/application.json.json_builder

Add json_builder to the Gemfile:

gem 'json_builder'
status response.status
error @error.to_json.html_safe
result JSON.parse(yield)

Using Rabl

Filename: app/views/layouts/application.rabl

node(:status) { response.status }
node(:error)  { @error.to_json.html_safe }

node(:result) do
  case content_type
  when :json
    Yajl::Parser.parse(yield)
  when :xml
    Nori.new.parse(yield)
  end
end

In this case, the rendered output of your .rabl will appear under the result field (or wherever the yield is placed in the layout file). The controller can pass metadata and error values via instance variables.

A yield by itself will only return the rendered template, which would be escaped HTML in the result node. But if you convert the rendered content back into a Hash, RABL will treat the yielded content the way you'd expect. So for other content types, call a parser that can convert the yield content into a Hash that can be understood by RABL.

This example may not work with Ruby 1.9 (1.9.2 and 1.9.3 in my case). So, if it raises No block given (yield), try to use Erb (the second one is the better one) or JsonBuilder layouts.
I haven't realize yet how to solve this problem.

Note that html_safe prevents Rails from auto-escaping the JSON output. The raw helper can also be used. This blog post explains the difference.

References