Skip to content

Support integrating with Action View layouts - #623

Open
seanpdoyle wants to merge 1 commit into
rails:mainfrom
seanpdoyle:action-view-layout
Open

Support integrating with Action View layouts#623
seanpdoyle wants to merge 1 commit into
rails:mainfrom
seanpdoyle:action-view-layout

Conversation

@seanpdoyle

@seanpdoyle seanpdoyle commented Sep 4, 2026

Copy link
Copy Markdown

Related to #250
Related to #172

Add support for Rails' built-in layout templates defined in app/views/layouts/. Layouts can be used to extract properties or structures that are shared across responses.

For example, a PostsController that inherits from ApplicationController will render its templates declared in app/views/posts/ into the layout declared in
app/views/layouts/application.json.jbuilder:

# app/views/layouts/application.json.jbuilder
json.merge! yield
json.servedAt Time.current

# app/views/posts/index.json.jbuilder
json.partial! 'posts/post', collection: @posts, as: :post

Related to rails#250
Related to rails#172

Add support for Rails' built-in layout templates defined in
`app/views/layouts/`. Layouts can be used to extract properties or
structures that are shared across responses.

For example, a `PostsController` that inherits from
`ApplicationController` will render its templates declared in
`app/views/posts/` *into* the layout declared in
`app/views/layouts/application.json.jbuilder`:

    # app/views/layouts/application.json.jbuilder
    json.merge! yield
    json.servedAt Time.current

    # app/views/posts/index.json.jbuilder
    json.partial! 'posts/post', collection: @posts, as: :post
@malomalo

malomalo commented Sep 4, 2026

Copy link
Copy Markdown

@seanpdoyle I maintain TurboStreamer it might be a better fit for you. It's a Jbuilder-ish DSL over streaming encoders (Oj/Yajl), and supports layouts and improved caching performance.

A layout calls json.yield! wherever the template's JSON belongs:

# app/views/layouts/application.json.streamer
json.object! do
  json.meta do
    json.object! { json.version 1 }
  end
  json.key! :data
  json.yield!
end

# app/views/posts/index.json.streamer
json.array! @posts, :id, :title

# => { "meta": { "version": 1 }, "data": [ { "id": 1, "title": "..." } ] }

The layout and the template share one builder, so the template writes straight into the same stream at the point it's yielded — nothing is encoded to a string and re-parsed, which also means the template's JSON can land at a key or inside an array rather than only merging into the root. This also enables streaming support.

More in the README. Happy to answer questions if you give it a look.

@seanpdoyle

Copy link
Copy Markdown
Author

@malomalo That seems like a compelling project, thanks for the recommendation!

I'm sure that there's plenty of innovation out there worth trying. The motivation behind this PR is less about innovating, and more about bringing jbuilder more in line with existing Action View and Rails conventions. Since jbuilder is part of most rails new-generated Gemfiles, I think many would benefit from any improvements.

supports layouts and improved caching performance.

That's exciting! Are there any opportunities to upstream performance improvements back into jbuilder?

@malomalo

malomalo commented Sep 5, 2026

Copy link
Copy Markdown

That's exciting! Are there any opportunities to upstream performance improvements back into jbuilder?

@seanpdoyle I tried for a while with my fork to get jBuilder off hashes at least partially but if i recall correctly it's impossible due to syntax and needing to know how to insert the string. I forget the concrete example convinced me it wasn't possible.

I just remember your coworkers did something similar recently - but was just looking to see how they resolved it but looking at the code now it was based of my work so not sure if they have the answers 🤣🙈. Just read the readme and recognized the performance graph, then I see Wankel in the Gemfile history and your analyzer is a fork of mine - Would have taken PRs but I guess copy pasta is the sincerest form of flattery in open source haha.

Looks like OJ got some performance improvements for this use case that I should bring in to turbostreamer that props brought in and add props to comparisons.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants