name: alba-inertia
description: >-
Alba serializers + Typelizer for type-safe Inertia Rails props with auto-generated TypeScript types. Use when
serializing models for Inertia responses, setting up Alba resources, generating TypeScript types from Ruby, or
using Inertia prop options (defer, once, merge, scroll) with Alba attributes. Replaces as_json with structured,
auto-typed ApplicationResource, page resources, and shared props resources. When active, OVERRIDES the
render inertia: { ... } pattern from other skills — use convention-based instance variable rendering instead.
Alba + Typelizer for Inertia Rails
Requires: alba, typelizer, alba-inertia gems in Gemfile.
Alba serializers for Inertia props with auto-generated TypeScript types.
Replaces as_json(only: [...]) with structured, type-safe resources.
Before creating a resource, ask:
- Reusable data shape (user, course)? → Entity resource (
UserResource) — shared across pages - Page-specific props bundle? → Page resource (
UsersIndexResource) — one per controller action - Global data (auth, notifications)? → Shared props resource (
SharedPropsResource)
NEVER:
- Use
as_jsonwhen Alba is set up — it bypasses type generation and creates untyped props - Skip
typelize_fromwhen resource name differs from model — Typelizer can't infer column types and generatesunknown - Put
declare moduleaugmentations inserializers/index.ts— Typelizer-generated types go inserializers/index.ts, manual InertiaConfig goes inglobals.d.ts
Setup
ApplicationResource (all resources inherit from this)
# app/resources/application_resource.rb
class ApplicationResource
include Alba::Resource
helper Typelizer::DSL # enables typelize, typelize_from
helper Alba::Inertia::Resource # enables inertia: option on attributes
include Rails.application.routes.url_helpers
end
Controller Integration
# app/controllers/inertia_controller.rb
class InertiaController < ApplicationController
include Alba::Inertia::Controller
inertia_share { SharedPropsResource.new(self).to_inertia }
end
Resource Types
Entity Resource (reusable data shape)
# app/resources/user_resource.rb
class UserResource < ApplicationResource
typelize_from User # needed when resource name doesn't match model
attributes :id, :name, :email
typelize :string?
attribute :avatar_url do |user|
user.avatar.attached? ? rails_blob_path(user.avatar, only_path: true) : nil
end
end
Page Resource (page-specific props)
# app/resources/users/index_resource.rb
# Naming convention: {Controller}{Action}Resource
class UsersIndexResource < ApplicationResource
has_many :users, resource: UserResource
typelize :string
attribute :search do |obj, _|
obj.params.dig(:filters, :search)
end
end
Shared Props Resource
Requires Rails Current attributes (e.g., Current.user) to be configured —
see CurrentAttributes.
# app/resources/shared_props_resource.rb
class SharedPropsResource < ApplicationResource
one :auth, source: proc { Current }
attribute :unread_messages_count, inertia: { always: true } do
Current.user&.unread_count || 0
end
has_many :live_now, resource: LiveSessionsResource,
inertia: { once: { expires_in: 5.minutes } }
end
Convention-Based Rendering
With Alba::Inertia::Controller, instance variables auto-serialize:
class UsersController < InertiaController
def index
@users = User.all # auto-serialized via UserResource
@filters = filter_params # plain data passed through
# Auto-detects UsersIndexResource
end
def show
@user = User.find(params[:id])
# Auto-detects UsersShowResource
end
end
Typelizer + Type Generation
typelize_from tells Typelizer which model to infer column types from — needed when
resource name doesn't match model. For computed attributes, declare types explicitly:
class AuthorResource < ApplicationResource
typelize_from User
attributes :id, :name, :email
typelize :string? # next attribute is string | undefined
attribute :avatar_url do |user|
rails_storage_proxy_path(user.avatar) if user.avatar.attached?
end
typelize filters: "{category: number}" # inline TS type
end
Types auto-generate when Rails server runs. Manual: bin/rake typelizer:generate.
Inertia Prop Options in Alba
The inertia: option on attributes/associations maps to InertiaRails prop types:
attribute :stats, inertia: :defer # InertiaRails.defer
has_many :users, inertia: :optional # InertiaRails.optional
has_many :countries, inertia: :once # InertiaRails.once
has_many :items, inertia: { merge: true } # InertiaRails.merge
attribute :csrf, inertia: { always: true } # InertiaRails.always
MANDATORY — READ ENTIRE FILE when using grouped defer, merge with match_on,
scroll props, or combining multiple options:
references/prop-options.md (~60 lines) — full syntax
for all inertia: option variants and inertia_prop alternative syntax.
Do NOT load for basic inertia: :defer, inertia: :optional, or
inertia: :once — the shorthand above is sufficient.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
TypeScript type is all unknown |
Missing typelize_from |
Add typelize_from ModelName when resource name doesn't match model |
inertia: option has no effect |
Missing helper | Ensure helper Alba::Inertia::Resource is in ApplicationResource |
| Types not regenerating | Server not running | Typelizer watches files in dev only. Run bin/rake typelizer:generate manually |
NoMethodError for typelize |
Missing helper | Ensure helper Typelizer::DSL is in ApplicationResource |
| Convention-based rendering picks wrong resource | Naming mismatch | Resource must be {Controller}{Action}Resource (e.g., UsersIndexResource for UsersController#index) |
to_inertia undefined |
Missing include | Controller needs include Alba::Inertia::Controller |
Related Skills
- Prop types →
inertia-rails-controllers(defer, once, merge, scroll) - TypeScript config →
inertia-rails-typescript(InertiaConfig in globals.d.ts)