Fetching contributors…
Cannot retrieve contributors at this time
283 lines (207 sloc) 6.8 KB


Jbuilder gives you a simple DSL for declaring JSON structures that beats manipulating giant hash structures. This is particularly helpful when the generation process is fraught with conditionals and loops. Here's a simple example:

# app/views/messages/show.json.jbuilder

json.content format_content(@message.content)
json.(@message, :created_at, :updated_at) do
  json.email_address @message.creator.email_address_with_name
  json.url url_for(@message.creator, format: :json)

if current_user.admin?
  json.visitors calculate_visitors(@message)

json.comments @message.comments, :content, :created_at

json.attachments @message.attachments do |attachment|
  json.filename attachment.filename
  json.url url_for(attachment)

This will build the following structure:

  "content": "<p>This is <i>serious</i> monkey business</p>",
  "created_at": "2011-10-29T20:45:28-05:00",
  "updated_at": "2011-10-29T20:45:28-05:00",

  "author": {
    "name": "David H.",
    "email_address": "'David Heinemeier Hansson' <>",
    "url": ""

  "visitors": 15,

  "comments": [
    { "content": "Hello everyone!", "created_at": "2011-10-29T20:45:28-05:00" },
    { "content": "To you my good sir!", "created_at": "2011-10-29T20:47:28-05:00" }

  "attachments": [
    { "filename": "forecast.xls", "url": "" },
    { "filename": "presentation.pdf", "url": "" }

To define attribute and structure names dynamically, use the set! method:

json.set! :author do
  json.set! :name, 'David'

# => {"author": { "name": "David" }}

To merge existing hash or array to current context:

hash = { author: { name: "David" } } do
  json.title "Merge HOWTO"
  json.merge! hash

# => "post": { "title": "Merge HOWTO", "author": { "name": "David" } }

Top level arrays can be handled directly. Useful for index and other collection actions.

# @comments = @post.comments

json.array! @comments do |comment|
  next if comment.marked_as_spam_by?(current_user)

  json.body comment.body do

# => [ { "body": "great post...", "author": { "first_name": "Joe", "last_name": "Bloe" }} ]

You can also extract attributes from array directly.

# @people = People.all

json.array! @people, :id, :name

# => [ { "id": 1, "name": "David" }, { "id": 2, "name": "Jamie" } ]

Jbuilder objects can be directly nested inside each other. Useful for composing objects.

class Person
  # ... Class Definition ... #
  def to_builder do |person|
      person.(self, :name, :age)

class Company
  # ... Class Definition ... #
  def to_builder do |company| name
      company.president president.to_builder

company ='Doodle Corp','John Stobs', 58))!

# => {"name":"Doodle Corp","president":{"name":"John Stobs","age":58}}

You can either use Jbuilder stand-alone or directly as an ActionView template language. When required in Rails, you can create views a la show.json.jbuilder (the json is already yielded):

# Any helpers available to views are available to the builder
json.content format_content(@message.content)
json.(@message, :created_at, :updated_at) do
  json.email_address @message.creator.email_address_with_name
  json.url url_for(@message.creator, format: :json)

if current_user.admin?
  json.visitors calculate_visitors(@message)

You can use partials as well. The following will render the file views/comments/_comments.json.jbuilder, and set a local variable comments with all this message's comments, which you can use inside the partial.

json.partial! 'comments/comments', comments: @message.comments

It's also possible to render collections of partials:

json.array! @posts, partial: 'posts/post', as: :post

# or

json.partial! 'posts/post', collection: @posts, as: :post

# or

json.partial! partial: 'posts/post', collection: @posts, as: :post

# or

json.comments @post.comments, partial: 'comments/comment', as: :comment

You can pass any objects into partial templates with or without :locals option.

json.partial! 'sub_template', locals: { user: user }

# or

json.partial! 'sub_template', user: user

You can explicitly make Jbuilder object return null if you want:

json.extract! @post, :id, :title, :content, :published_at do
  if @post.anonymous?
    json.null! # or json.nil!
    json.first_name @post.author_first_name
    json.last_name @post.author_last_name

To prevent Jbuilder from including null values in the output, you can use the ignore_nil! method:

json.ignore_nil! nil "bar"
# => { "bar": "bar" }

Fragment caching is supported, it uses Rails.cache and works like caching in HTML templates:

json.cache! ['v1', @person], expires_in: 10.minutes do
  json.extract! @person, :name, :age

You can also conditionally cache a block by using cache_if! like this:

json.cache_if! !admin?, ['v1', @person], expires_in: 10.minutes do
  json.extract! @person, :name, :age

If you are rendering fragments for a collection of objects, have a look at jbuilder_cache_multi gem. It uses fetch_multi (>= Rails 4.1) to fetch multiple keys at once.

Keys can be auto formatted using key_format!, this can be used to convert keynames from the standard ruby_format to camelCase:

json.key_format! camelize: :lower
json.first_name 'David'

# => { "firstName": "David" }

You can set this globally with the class method key_format (from inside your environment.rb for example):

Jbuilder.key_format camelize: :lower

Faster JSON backends

Jbuilder uses MultiJson, which by default will use the JSON gem. That gem is currently tangled with ActiveSupport's all-Ruby #to_json implementation, which is slow (fixed in Rails >= 4.1). For faster Jbuilder rendering, you can specify something like the Yajl JSON generator instead. You'll need to include the yajl-ruby gem in your Gemfile and then set the following configuration for MultiJson:

require 'multi_json'
MultiJson.use :yajl

Contributing to Jbuilder

Jbuilder is the work of many contributors. You're encouraged to submit pull requests, propose features and discuss issues.



Jbuilder is released under the MIT License.