{"id":13427843,"url":"https://github.com/rails/jbuilder","last_synced_at":"2025-05-12T03:39:23.982Z","repository":{"id":1932363,"uuid":"2861056","full_name":"rails/jbuilder","owner":"rails","description":"Jbuilder: generate JSON objects with a Builder-style DSL","archived":false,"fork":false,"pushed_at":"2025-04-04T00:14:28.000Z","size":647,"stargazers_count":4369,"open_issues_count":51,"forks_count":441,"subscribers_count":85,"default_branch":"main","last_synced_at":"2025-05-09T12:39:02.685Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rails.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2011-11-27T14:02:35.000Z","updated_at":"2025-05-08T09:03:33.000Z","dependencies_parsed_at":"2024-11-06T06:05:01.302Z","dependency_job_id":"7a8f1f51-3ad8-441c-af18-7df8eb8f5aeb","html_url":"https://github.com/rails/jbuilder","commit_stats":{"total_commits":630,"total_committers":147,"mean_commits":4.285714285714286,"dds":0.6111111111111112,"last_synced_commit":"9aa3dd9d0e8142d58108ea00fdcc6cabda1df18d"},"previous_names":[],"tags_count":74,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rails%2Fjbuilder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rails%2Fjbuilder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rails%2Fjbuilder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rails%2Fjbuilder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rails","download_url":"https://codeload.github.com/rails/jbuilder/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253418941,"owners_count":21905334,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T01:00:41.224Z","updated_at":"2025-05-12T03:39:23.942Z","avatar_url":"https://github.com/rails.png","language":"Ruby","readme":"# Jbuilder\n\nJbuilder gives you a simple DSL for declaring JSON structures that beats\nmanipulating giant hash structures. This is particularly helpful when the\ngeneration process is fraught with conditionals and loops. Here's a simple\nexample:\n\n```ruby\n# app/views/messages/show.json.jbuilder\n\njson.content format_content(@message.content)\njson.(@message, :created_at, :updated_at)\n\njson.author do\n  json.name @message.creator.name.familiar\n  json.email_address @message.creator.email_address_with_name\n  json.url url_for(@message.creator, format: :json)\nend\n\nif current_user.admin?\n  json.visitors calculate_visitors(@message)\nend\n\njson.comments @message.comments, :content, :created_at\n\njson.attachments @message.attachments do |attachment|\n  json.filename attachment.filename\n  json.url url_for(attachment)\nend\n```\n\nThis will build the following structure:\n\n```javascript\n{\n  \"content\": \"\u003cp\u003eThis is \u003ci\u003eserious\u003c/i\u003e monkey business\u003c/p\u003e\",\n  \"created_at\": \"2011-10-29T20:45:28-05:00\",\n  \"updated_at\": \"2011-10-29T20:45:28-05:00\",\n\n  \"author\": {\n    \"name\": \"David H.\",\n    \"email_address\": \"'David Heinemeier Hansson' \u003cdavid@heinemeierhansson.com\u003e\",\n    \"url\": \"http://example.com/users/1-david.json\"\n  },\n\n  \"visitors\": 15,\n\n  \"comments\": [\n    { \"content\": \"Hello everyone!\", \"created_at\": \"2011-10-29T20:45:28-05:00\" },\n    { \"content\": \"To you my good sir!\", \"created_at\": \"2011-10-29T20:47:28-05:00\" }\n  ],\n\n  \"attachments\": [\n    { \"filename\": \"forecast.xls\", \"url\": \"http://example.com/downloads/forecast.xls\" },\n    { \"filename\": \"presentation.pdf\", \"url\": \"http://example.com/downloads/presentation.pdf\" }\n  ]\n}\n```\n\n## Dynamically Defined Attributes\n\nTo define attribute and structure names dynamically, use the `set!` method:\n\n```ruby\njson.set! :author do\n  json.set! :name, 'David'\nend\n\n# =\u003e {\"author\": { \"name\": \"David\" }}\n```\n\n## Merging Existing Hash or Array\n\nTo merge existing hash or array to current context:\n\n```ruby\nhash = { author: { name: \"David\" } }\njson.post do\n  json.title \"Merge HOWTO\"\n  json.merge! hash\nend\n\n# =\u003e \"post\": { \"title\": \"Merge HOWTO\", \"author\": { \"name\": \"David\" } }\n```\n\n## Top Level Arrays\n\nTop level arrays can be handled directly. Useful for index and other collection actions.\n\n```ruby\n# @comments = @post.comments\n\njson.array! @comments do |comment|\n  next if comment.marked_as_spam_by?(current_user)\n\n  json.body comment.body\n  json.author do\n    json.first_name comment.author.first_name\n    json.last_name comment.author.last_name\n  end\nend\n\n# =\u003e [ { \"body\": \"great post...\", \"author\": { \"first_name\": \"Joe\", \"last_name\": \"Bloe\" }} ]\n```\n\n## Array Attributes\n\nYou can also extract attributes from array directly.\n\n```ruby\n# @people = People.all\n\njson.array! @people, :id, :name\n\n# =\u003e [ { \"id\": 1, \"name\": \"David\" }, { \"id\": 2, \"name\": \"Jamie\" } ]\n```\n\n## Plain Arrays\n\nTo make a plain array without keys, construct and pass in a standard Ruby array.\n\n```ruby\nmy_array = %w(David Jamie)\n\njson.people my_array\n\n# =\u003e \"people\": [ \"David\", \"Jamie\" ]\n```\n\n## Child Objects\n\nYou don't always have or need a collection when building an array.\n\n```ruby\njson.people do\n  json.child! do\n    json.id 1\n    json.name 'David'\n  end\n  json.child! do\n    json.id 2\n    json.name 'Jamie'\n  end\nend\n\n# =\u003e { \"people\": [ { \"id\": 1, \"name\": \"David\" }, { \"id\": 2, \"name\": \"Jamie\" } ] }\n```\n\n## Nested Jbuilder Objects\n\nJbuilder objects can be directly nested inside each other. Useful for composing objects.\n\n```ruby\nclass Person\n  # ... Class Definition ... #\n  def to_builder\n    Jbuilder.new do |person|\n      person.(self, :name, :age)\n    end\n  end\nend\n\nclass Company\n  # ... Class Definition ... #\n  def to_builder\n    Jbuilder.new do |company|\n      company.name name\n      company.president president.to_builder\n    end\n  end\nend\n\ncompany = Company.new('Doodle Corp', Person.new('John Stobs', 58))\ncompany.to_builder.target!\n\n# =\u003e {\"name\":\"Doodle Corp\",\"president\":{\"name\":\"John Stobs\",\"age\":58}}\n```\n\n## Rails Integration\n\nYou can either use Jbuilder stand-alone or directly as an ActionView template\nlanguage. When required in Rails, you can create views à la show.json.jbuilder\n(the json is already yielded):\n\n```ruby\n# Any helpers available to views are available to the builder\njson.content format_content(@message.content)\njson.(@message, :created_at, :updated_at)\n\njson.author do\n  json.name @message.creator.name.familiar\n  json.email_address @message.creator.email_address_with_name\n  json.url url_for(@message.creator, format: :json)\nend\n\nif current_user.admin?\n  json.visitors calculate_visitors(@message)\nend\n```\n\n## Partials\n\nYou can use partials as well. The following will render the file\n`views/comments/_comments.json.jbuilder`, and set a local variable\n`comments` with all this message's comments, which you can use inside\nthe partial.\n\n```ruby\njson.partial! 'comments/comments', comments: @message.comments\n```\n\nIt's also possible to render collections of partials:\n\n```ruby\njson.array! @posts, partial: 'posts/post', as: :post\n\n# or\njson.partial! 'posts/post', collection: @posts, as: :post\n\n# or\njson.partial! partial: 'posts/post', collection: @posts, as: :post\n\n# or\njson.comments @post.comments, partial: 'comments/comment', as: :comment\n```\n\nThe `as: :some_symbol` is used with partials. It will take care of mapping the passed in object to a variable for the\npartial. If the value is a collection either implicitly or explicitly by using the `collection:` option, then each\nvalue of the collection is passed to the partial as the variable `some_symbol`. If the value is a singular object,\nthen the object is passed to the partial as the variable `some_symbol`.\n\nBe sure not to confuse the `as:` option to mean nesting of the partial. For example:\n\n```ruby\n# Use the default `views/comments/_comment.json.jbuilder`, putting @comment as the comment local variable.\n# Note, `comment` attributes are \"inlined\".\njson.partial! @comment, as: :comment\n```\n\nis quite different from:\n\n```ruby\n# comment attributes are nested under a \"comment\" property\njson.comment do\n  json.partial! \"/comments/comment.json.jbuilder\", comment: @comment\nend\n```\n\nYou can pass any objects into partial templates with or without `:locals` option.\n\n```ruby\njson.partial! 'sub_template', locals: { user: user }\n\n# or\n\njson.partial! 'sub_template', user: user\n```\n\n## Null Values\n\nYou can explicitly make Jbuilder object return null if you want:\n\n```ruby\njson.extract! @post, :id, :title, :content, :published_at\njson.author do\n  if @post.anonymous?\n    json.null! # or json.nil!\n  else\n    json.first_name @post.author_first_name\n    json.last_name @post.author_last_name\n  end\nend\n```\n\nTo prevent Jbuilder from including null values in the output, you can use the `ignore_nil!` method:\n\n```ruby\njson.ignore_nil!\njson.foo nil\njson.bar \"bar\"\n# =\u003e { \"bar\": \"bar\" }\n```\n\n## Caching\n\nFragment caching is supported, it uses `Rails.cache` and works like caching in\nHTML templates:\n\n```ruby\njson.cache! ['v1', @person], expires_in: 10.minutes do\n  json.extract! @person, :name, :age\nend\n```\n\nYou can also conditionally cache a block by using `cache_if!` like this:\n\n```ruby\njson.cache_if! !admin?, ['v1', @person], expires_in: 10.minutes do\n  json.extract! @person, :name, :age\nend\n```\n\nAside from that, the `:cached` options on collection rendering is available on Rails \u003e= 6.0. This will cache the\nrendered results effectively using the multi fetch feature.\n\n```ruby\njson.array! @posts, partial: \"posts/post\", as: :post, cached: true\n\n# or:\njson.comments @post.comments, partial: \"comments/comment\", as: :comment, cached: true\n```\n\nIf your collection cache depends on multiple sources (try to avoid this to keep things simple), you can name all these dependencies as part of a block that returns an array:\n\n```ruby\njson.array! @posts, partial: \"posts/post\", as: :post, cached: -\u003e post { [post, current_user] }\n```\n\nThis will include both records as part of the cache key and updating either of them will expire the cache.\n\n## Formatting Keys\n\nKeys can be auto formatted using `key_format!`, this can be used to convert\nkeynames from the standard ruby_format to camelCase:\n\n```ruby\njson.key_format! camelize: :lower\njson.first_name 'David'\n\n# =\u003e { \"firstName\": \"David\" }\n```\n\nYou can set this globally with the class method `key_format` (from inside your\nenvironment.rb for example):\n\n```ruby\nJbuilder.key_format camelize: :lower\n```\n\nBy default, key format is not applied to keys of hashes that are\npassed to methods like `set!`, `array!` or `merge!`. You can opt into\ndeeply transforming these as well:\n\n```ruby\njson.key_format! camelize: :lower\njson.deep_format_keys!\njson.settings([{some_value: \"abc\"}])\n\n# =\u003e { \"settings\": [{ \"someValue\": \"abc\" }]}\n```\n\nYou can set this globally with the class method `deep_format_keys` (from inside your\nenvironment.rb for example):\n\n```ruby\nJbuilder.deep_format_keys true\n```\n\n## Testing JBuilder Response body with RSpec\n\nTo test the response body of your controller spec, enable `render_views` in your RSpec context. This [configuration](https://rspec.info/features/6-0/rspec-rails/controller-specs/render-views) renders the views in a controller test.\n\n## Contributing to Jbuilder\n\nJbuilder is the work of many contributors. You're encouraged to submit pull requests, propose\nfeatures and discuss issues.\n\nSee [CONTRIBUTING](CONTRIBUTING.md).\n\n## License\n\nJbuilder is released under the [MIT License](http://www.opensource.org/licenses/MIT).\n","funding_links":[],"categories":["`API Frameworks`","API","Web Apps, Services \u0026 Interaction","Ruby","API Builder and Discovery","API Builder","RESTful API","API Frameworks","Serialization","Serializers"],"sub_categories":["`Ruby`","Omniauth","API Builders","Ruby"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frails%2Fjbuilder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frails%2Fjbuilder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frails%2Fjbuilder/lists"}