Skip to content

kikyous/inertia_jb

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

InertiaJb

InertiaJb lets you declare Inertia.js props for your Rails frontend components inside view templates, using plain Ruby Hashes powered by jb.

It is built on top of the inertia-rails gem.

A *.html.inertia template is just Ruby code whose last expression is a Hash. That Hash is handed straight to InertiaRails::Renderer, so every Inertia protocol feature works out of the box — partial reloads (at any nesting depth), optional / always / deferred / scroll props, prop merging, shared data, and global key transforms.

# app/controllers/messages_controller.rb
class MessagesController < ApplicationController
  # Shared props are merged in automatically.
  inertia_share user: -> { Current.user }

  def show
    @message = Message.find(params[:id])
  end
end
# app/views/messages/show.html.inertia
{
  message: {
    content: @message.content,
    author: {
      name: @message.author.name,
      email: @message.author.email,
      url: url_for(@message.author, format: :json)
    },
    comments: render(partial: "comments/comment", collection: @message.comments)
  }
}
// app/javascript/pages/messages/show.jsx
export default function Message({ user, message }) {
  return (
    <div>
      <p>Hi, {user.name}</p>
      <p>{message.content}</p>
      <a href={message.author.url}>
        {message.author.name} &lt;{message.author.email}&gt;
      </a>
      {message.comments.map((c) => <Comment key={c.id} comment={c} />)}
    </div>
  );
}

Why jb?

Inertia's server side is fundamentally about producing a Hash of props that inertia-rails then resolves and serializes. jb templates are plain Ruby Hashes, so there is zero impedance mismatch: no DSL to learn, no intermediate representation, and the full power of Ruby for building collections and conditionals.

Coming from props_template? That gem streams JSON strings, which don't map cleanly onto Inertia's Hash-based resolver. jb's plain-Hash output is the natural fit, which is why this gem is built on it.

Installation

Add the gem to your Gemfile:

gem "inertia_jb"

Then, in your inertia-rails initializer, disable default_render so that a normal implicit render falls through to your .html.inertia template:

# config/initializers/inertia_rails.rb
InertiaRails.configure do |config|
  config.default_render = false
end

You do not need to call use_inertia_instance_props.

Layout

On an initial (non-XHR) page load the data-page root element is wrapped in a layout; Inertia (XHR) visits always return a bare JSON body with no layout.

The layout is chosen from inertia-rails' config.layout, matching InertiaRails::Renderer's own semantics:

# config/initializers/inertia_rails.rb
InertiaRails.configure do |config|
  config.default_render = false

  # config.layout = true      # (default) use the controller's normal layout
  # config.layout = "inertia" # use app/views/layouts/inertia.html.erb
  # config.layout = false     # no layout — render just the <div id="app"> root
end
  • true / nil — the controller's default layout, resolved the normal Rails way (app/views/layouts/application.html.erb, or any layout "..." declaration in the controller).
  • A String — that named layout (app/views/layouts/<name>.html.erb).
  • false — no layout at all; the response is only the <div id="app" data-page="…"> root, so you provide <html>/<head>/asset tags elsewhere.

Because config.layout is scoped per controller in inertia-rails, you can also set it on a single controller with inertia_config layout: "...". Plain (non-Inertia) .html.erb actions in the same app keep their layout regardless of this setting.

Note: this gem does not perform server-side rendering (SSR), so inertia_ssr_head in your layout will always be empty.

Templates and partials

  • Page templates live at app/views/<controller>/<action>.html.inertia and must return a Hash (your Inertia props).
  • Partials are ordinary jb partials named _name.html.jb. They return a Hash, and compose naturally:
# app/views/messages/show.html.inertia
{
  author:   render(partial: "authors/author", object: @message.author),
  comments: render(partial: "comments/comment", collection: @message.comments)
}
# app/views/authors/_author.html.jb
{ id: author.id, name: author.name }

render(partial:, collection:) returns an array of Hashes (thanks to jb), which you embed directly. Don't name partials .html.inertia — that extension triggers the Inertia response wrapper and is only for top-level page templates.

Inertia prop types

Because props are just a Hash, Inertia's special prop types are plain values you drop in. Inside a .html.inertia template you can use the short helpers (optional, always, defer, scroll, merge, deep_merge) or the full InertiaRails.* methods.

{
  id:    @post.id,
  title: @post.title,

  # Only fetched when explicitly requested in a partial reload.
  stats: optional { @post.expensive_stats },

  # Always fetched, even if not requested in a partial reload.
  settings: always { current_settings },

  # Excluded from the initial load; fetched in a follow-up request.
  comments: defer(group: :comments) {
    render(partial: "comments/comment", collection: @post.comments)
  },

  # Infinite scrolling (accepts a paginator or explicit metadata).
  feed: scroll(@pagy) {
    render(partial: "feed/item", collection: @items)
  }
}

See the inertia-rails docs for partial reloads, deferred props, and infinite scroll.

Caching

Use plain Rails caching — you're caching Ruby Hashes:

@posts.map do |post|
  Rails.cache.fetch(post) { render(partial: "posts/post", object: post) }
end

camelCase keys

If you configure inertia-rails' prop_transformer to camelize keys, it applies at every nesting depth — because your props reach inertia-rails as a real Hash:

# config/initializers/inertia_rails.rb
InertiaRails.configure do |config|
  config.default_render = false
  config.prop_transformer = ->(props:) { props.deep_transform_keys { |k| k.to_s.camelize(:lower) } }
end

Alternatively, just write camelCase keys directly in your templates.

Notes

  • Inertia props must be an object, so page templates should return a Hash (not a top-level Array).
  • Don't install this alongside inertia-builder; both register an :inertia template handler.

Development

bundle install
bundle exec rake test

License

MIT. See LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages