alba-inertia

>-

inertia-rails/skills344 installsMITSynced Aug 26

Works with

Claude CodeCursorCodex CLIGitHub CopilotGemini CLI
---
name: alba-inertia
description: >-
license: MIT
---

# 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_json` when Alba is set up — it bypasses type generation and creates untyped props
- Skip `typelize_from` when resource name differs from model — Typelizer can't infer column types and generates `unknown`
- Put `declare module` augmentations in `serializers/index.ts` — Typelizer-generated types go in `serializers/index.ts`, manual InertiaConfig goes in `globals.d.ts`

## Setup

### ApplicationResource (all resources inherit from this)

```ruby
# 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

```ruby
# 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)

```ruby
# 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)

```ruby
# 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](https://api.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html).

```ruby
# 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:

```ruby
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:

```ruby
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:

```ruby
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`](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)

More General & Other skills

← All General & Other skills

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY