Database
Charming can generate SQLite-backed apps with Active Record. Database support is opt-in; apps without it continue to use only session-backed state in app/state. The activerecord and sqlite3 gems are dependencies of your app (added by the generator), not of the framework.
New App
Generate an app with SQLite support:
charming new todos_tui --database sqlite3
This adds:
app/models/application_record.rb
config/database.rb
db/migrate/.keep
db/seeds.rb
Environments
config/database.rb selects the database file from CHARMING_ENV (default development):
environment = ENV["CHARMING_ENV"] || "development"
database_path = File.expand_path("../db/#{environment}.sqlite3", __dir__)
So db/development.sqlite3, db/test.sqlite3, and db/production.sqlite3 stay separate. In framework and app code, Charming.env returns a string inquirer:
Charming.env # => "development"
Charming.env.test? # => false
Charming.env.production? # => false
Generated specs pin CHARMING_ENV=test before the app loads (see Testing), so the test suite never touches your development data.
Existing App
Install SQLite support into an existing Charming app from the app root:
charming db:install sqlite3
This creates the same database files, updates the generated gemspec with Active Record dependencies, and updates lib/my_app.rb to load config/database.rb and app/models.
State vs Models
Use state classes for in-memory TUI state:
def home
state(:home, HomeState)
end
Use Active Record models for persisted data:
def show
render :show,
home: home,
todos: Todo.order(:created_at)
end
Generate A Model
Generate a persisted model and migration:
charming generate model todo title:string done:boolean
This creates:
app/models/todo.rb
db/migrate/20260531000000_create_todos.rb
spec/models/todo_spec.rb
Generated models inherit from ApplicationRecord:
module TodosTui
class Todo < ApplicationRecord
end
end
Generate A Migration
Standalone migrations follow Rails naming conventions:
charming g migration create_posts title:string body:text
charming g migration add_email_to_users email:string
charming g migration remove_email_from_users email:string
charming g migration tune_indexes # empty change method to fill in
create_<table> builds a create_table block (with t.timestamps), add_<x>_to_<table> emits add_column lines, remove_<x>_from_<table> emits remove_column lines. Migration versions are guaranteed unique even when two generators run within the same second.
Database Commands
Run database commands from the app root. The target database follows CHARMING_ENV:
| Command | Does |
|---|---|
charming db:create | Create the database file and connect. |
charming db:migrate | Run pending migrations, then refresh db/schema.rb. |
charming db:rollback [STEP=n] | Roll back the last n migrations (default 1), then refresh the schema. |
charming db:drop | Delete the database file. |
charming db:seed | Load db/seeds.rb (the app is loaded first, so seeds can use your models). |
charming db:setup | Create + load schema (or migrate) + seed, in one command. |
charming db:reset | Drop, then setup. |
charming db:prepare | CI-friendly: setup when the database is missing, otherwise just migrate. |
charming db:status | Print the migration status table (up/down per version). |
charming db:version | Print the current schema version. |
charming db:schema:dump | Write the current structure to db/schema.rb. |
charming db:schema:load | Load db/schema.rb — fast fresh setup without replaying migrations. |
charming db:install sqlite3 | Retrofit database support into an existing app. |
CHARMING_ENV=test charming db:prepare # prepare the test database
charming db:rollback STEP=3 # roll back three migrations