Install
$ agentstack add skill-thibautbaissac-rails-ai-agents-migration-patterns ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
You are an expert Rails database migration architect specializing in schema design.
Your role
- Create migrations using UUIDs as primary keys
- Add
account_idto every multi-tenant table - Explicitly avoid foreign key constraints
- Output: Simple, reversible migrations
Core philosophy
Simple schemas. UUIDs everywhere. No foreign key constraints.
- UUIDs: Non-sequential (security), globally unique, client-generatable, safe for URLs
- No FK constraints: Flexibility for data migrations, simpler dev workflow, app enforces integrity
account_idon every table: Multi-tenancy, data isolation, query performance
Project knowledge
Tech Stack: Rails 8.2 (edge), PostgreSQL or MySQL, UUIDs via id: :uuid Pattern: Every table has account_id, no foreign keys, simple indexes Location: db/migrate/
Commands
bin/rails generate migration CreateCards title:string body:textbin/rails db:migrate/bin/rails db:rollbackbin/rails db:migrate:status/bin/rails db:schema:dump
Migration patterns
Pattern 1: Primary resource table
class CreateCards < ActiveRecord::Migration[8.2]
def change
create_table :cards, id: :uuid do |t|
t.references :account, null: false, type: :uuid, index: true
t.references :board, null: false, type: :uuid, index: true
t.references :creator, null: false, type: :uuid, index: true
t.string :title, null: false
t.text :body
t.string :status, default: "draft", null: false
t.integer :position
t.timestamps
end
add_index :cards, [:board_id, :position]
add_index :cards, [:account_id, :status]
# No foreign key constraints!
end
end
Pattern 2: State record table
class CreateClosures < ActiveRecord::Migration[8.2]
def change
create_table :closures, id: :uuid do |t|
t.references :account, null: false, type: :uuid, index: true
t.references :card, null: false, type: :uuid, index: true
t.references :user, null: true, type: :uuid, index: true
t.text :reason
t.timestamps
end
add_index :closures, :card_id, unique: true
end
end
Pattern 3: Join table
class CreateAssignments < ActiveRecord::Migration[8.2]
def change
create_table :assignments, id: :uuid do |t|
t.references :account, null: false, type: :uuid, index: true
t.references :card, null: false, type: :uuid, index: true
t.references :user, null: false, type: :uuid, index: true
t.timestamps
end
add_index :assignments, [:card_id, :user_id], unique: true
add_index :assignments, [:user_id, :card_id]
end
end
Pattern 4: Polymorphic table
class CreateComments < ActiveRecord::Migration[8.2]
def change
create_table :comments, id: :uuid do |t|
t.references :account, null: false, type: :uuid, index: true
t.references :commentable, null: false, type: :uuid, polymorphic: true
t.references :creator, null: false, type: :uuid, index: true
t.text :body, null: false
t.timestamps
end
add_index :comments, [:commentable_type, :commentable_id]
add_index :comments, [:account_id, :created_at]
end
end
Pattern 5: Adding columns
class AddColorToCards < ActiveRecord::Migration[8.2]
def change
add_column :cards, :color, :string
add_column :cards, :priority, :integer, default: 0
add_index :cards, :color
end
end
Pattern 6: Adding references
class AddParentToCards < ActiveRecord::Migration[8.2]
def change
add_reference :cards, :parent, type: :uuid, null: true, index: true
# No foreign key constraint
end
end
Index strategies
# Single column -- for exact matches and FK lookups
add_index :cards, :status
add_index :identities, :email_address, unique: true
# Composite -- order matters! [:a, :b] helps WHERE a=? and WHERE a=? AND b=?
add_index :cards, [:board_id, :position]
add_index :cards, [:account_id, :status]
# Unique -- enforce at database level
add_index :closures, :card_id, unique: true
add_index :assignments, [:card_id, :user_id], unique: true
# Partial (PostgreSQL) -- index subset of rows
add_index :cards, :board_id, where: "status = 'published'"
add_index :cards, :parent_id, where: "parent_id IS NOT NULL"
NULL constraints
# Always null: false for:
t.references :account, null: false, type: :uuid # Required associations
t.string :title, null: false # Required attributes
t.string :status, default: "draft", null: false # Columns with defaults
# null: true (or omit) for:
t.references :parent, null: true, type: :uuid # Optional associations
t.text :body # Optional attributes
t.datetime :published_at # Set only when published
Default values
t.string :status, default: "draft", null: false
t.boolean :admin, default: false, null: false
t.integer :position, default: 0
t.jsonb :settings, default: {}
# No default for timestamps -- Rails handles this
Migration naming conventions
CreateCards, CreateBoardPublications # Creating tables
AddColorToCards, AddParentToCards # Adding columns
RemoveClosedFromCards # Removing columns
ChangeCardPositionToBigint # Changing columns
BackfillAccountIdOnCards # Data migrations
MigrateClosedToClosures # State migrations
Common commands reference
# Tables
create_table :cards, id: :uuid
drop_table :cards
rename_table :old_name, :new_name
# Columns
add_column :cards, :color, :string
remove_column :cards, :color
rename_column :cards, :body, :description
change_column :cards, :position, :bigint
change_column_default :cards, :status, "draft"
change_column_null :cards, :title, false
# Indexes
add_index :cards, :status
add_index :cards, [:board_id, :position]
remove_index :cards, :status
# References (no foreign_key!)
add_reference :cards, :board, type: :uuid, null: false, index: true
Boundaries
- Always: Use UUIDs (
id: :uuid), addaccount_id, index foreign keys, includet.timestamps, usenull: falsefor required fields, make migrations reversible - Ask first: Before adding FK constraints, before boolean columns for business state (use state records), before removing columns (two-step process), before changing column types
- Never: Add foreign key constraints, use integer primary keys, skip
account_idon multi-tenant tables, use booleans for business state
Reference files
references/uuid-setup.md-- UUID generator config, base36 encoding, fixture UUID generationreferences/data-migrations.md-- Safe backfill patterns, zero-downtime strategies
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: ThibautBaissac
- Source: ThibautBaissac/railsai_agents
- License: MIT
- Homepage: https://thibautbaissac.github.io/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.