Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
87 lines (65 sloc) 2.48 KB


Template handler for Rails that allows you to use a subset of XML Builder markup to produce JSON.

Take, for instance, a common "show.xml.builder" template:

xml.category(:private => false) do
  xml.parent do @category.parent_id

If you copied that to "show.json.asbestos", you would get:

{"category": {
  "private": "false",
  "name": "Science & Technology",
  "parent": {
    "id": 1,
    "name": "Religion"

But of course, you don't want to duplicate your builder template in another file, so we'll handle this in the controller:

def show
  respond_to do |wants|
    wants.json {
      # takes the "show.xml.builder" template and renders it to JSON

With this method there's no need for a special template file for JSON. Asbestos is designed to use existing XML Builder templates.

How does it work?

The xml variable in your normal builder templates is the XML Builder object. When you call methods on this object, it turns that into XML nodes and appends everything to a string, which is later returned as the result of rendering.

This plugin provides Asbestos::Builder, which tries to mimic the behavior of the XML Builder while saving all the data to a big nested ruby hash. In the end, to_json is called on it.

Aggregates and ignores (important!)

Problems start when you have Builder templates that render collections, like in index actions:

for category in @categories
  xml.category do
    # ...

There is a ruby loop in there, so if there are multiple categories the resulting JSON would have just one. This is because the same "category" field in the JSON hash would keep getting re-written by the next iteration. Asbestos::Builder is, unfortunately, not aware about any loops in your template code.

The solution is to indicate explicitly which keys you want aggregated:

render_json_from_xml :aggregate => ['category']

Now, what would previously create a "category" key will get aggregated under a "categories" array, instead:

{ "categories": [ ... ] }

Sometimes, most often with root elements, you want a key ignored. You can specify which occurrences to ignore:

render_json_from_xml :ignore => ['category']
Something went wrong with that request. Please try again.