Skip to content
Discord Get Started

Rails

Rails uses the standard pg gem and ActiveRecord’s PostgreSQL adapter. The current DB9 deployment blocks connection initialization with Rails 8.1.4, as described below.

Terminal
db9 create --name rails-app

db9 create prints the connection string, with the admin password, once — copy it from the Connection String: line. It has this shape:

Output
postgresql://YOUR_TENANT_ID.admin:YOUR_PASSWORD@pg.d0000.db9.io:5432/postgres

YOUR_TENANT_ID is the tenant ID prefix in the generated connection string. Copy the username from the Connection String: line printed by db9 create or from db9 db connect. The examples below use pg.db9.io:5433, which reaches the same server; either host and port works. db9 db status rails-app shows the connection string without the password; if you lose it, db9 db reset-password rails-app sets a new password and prints a new connection string.

Settings that take the password on its own need it unencoded: the connection string URL-encodes it (%2B is +, %3D is =), while db9 create --show-password and db9 db reset-password also print it as plain text on the Admin Pass: line.

Set the connection string as an environment variable:

Terminal
export DATABASE_URL="postgresql://YOUR_TENANT_ID.admin:YOUR_PASSWORD@pg.db9.io:5433/postgres?sslmode=require"
Terminal
rails new rails-db9 --database=postgresql
cd rails-db9

The --database=postgresql flag adds the pg gem to your Gemfile and generates the correct config/database.yml template.

The simplest approach is to use the DATABASE_URL environment variable. Rails will pick it up automatically.

To configure directly, edit config/database.yml:

config/database.yml
default: &default
adapter: postgresql
host: pg.db9.io
port: 5433
database: postgres
username: YOUR_TENANT_ID.admin
password: <%= ENV["DB9_PASSWORD"] %>
sslmode: require
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
timeout: 5000
development:
<<: *default
test:
<<: *default
production:
<<: *default
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 10 } %>

Generate a User model:

Terminal
rails generate model User name:string email:string

Generate a Post model with a foreign key to User:

Terminal
rails generate model Post title:string body:text published:boolean user:references

Edit the generated models to add validations and associations:

app/models/user.rb
class User < ApplicationRecord
has_many :posts, dependent: :destroy
validates :name, presence: true
validates :email, presence: true, uniqueness: true
end
app/models/post.rb
class Post < ApplicationRecord
belongs_to :user
validates :title, presence: true
end
Terminal
rails db:migrate

Generate a Users controller:

Terminal
rails generate controller Users

Add a simple CRUD controller:

app/controllers/users_controller.rb
class UsersController < ApplicationController
def index
@users = User.all
render json: @users
end
def show
@user = User.find(params[:id])
render json: @user, include: :posts
end
def create
@user = User.new(user_params)
if @user.save
render json: @user, status: :created
else
render json: { errors: @user.errors }, status: :unprocessable_entity
end
end
def update
@user = User.find(params[:id])
if @user.update(user_params)
render json: @user
else
render json: { errors: @user.errors }, status: :unprocessable_entity
end
end
def destroy
User.find(params[:id]).destroy
head :no_content
end
private
def user_params
params.require(:user).permit(:name, :email)
end
end

Wire up the routes:

config/routes.rb
Rails.application.routes.draw do
resources :users
end

Start the server and test:

Terminal
rails server
curl http://localhost:3000/users
  • Host and port: pg.db9.io:5433 and the pg.d0000.db9.io:5432 that db9 create prints reach the same server; port 5432 works on either host.
  • TLS: Always use sslmode=require in your connection string or database.yml.
  • Connection pool size: Set pool in database.yml to match RAILS_MAX_THREADS. Start with 5–10 connections.
  • Database name: The database is always postgres. Do not run rails db:create — it will fail because the database already exists and you cannot create new ones.
  • Puma threads: If using Puma, ensure the pool size in database.yml is at least equal to RAILS_MAX_THREADS to avoid connection checkout timeouts.

DB9 accepts port 5432 as well as 5433, so the client is not reaching DB9 at all. A refusal from localhost or 127.0.0.1 means Rails did not get the DB9 host — check that DATABASE_URL is set, or that host is set in database.yml.

The postgres database already exists on DB9. Skip db:create and run db:migrate directly.

Verify that your username follows the format <tenant_id>.admin. Use the complete username from the generated connection string or db9 db connect; rails-app.admin fails even with the right password. DB9 routes pgwire connections by the tenant ID prefix. Also confirm sslmode=require is set.

DB9 connects you to the postgres database with admin privileges for your tenant. If you see schema-related errors, confirm you are not trying to modify system tables or create additional databases.

The first connection to DB9 may take slightly longer due to TLS handshake and tenant routing. Subsequent requests reuse pooled connections. Preload the connection pool by adding an initializer:

config/initializers/db9_warmup.rb
ActiveRecord::Base.connection_pool.checkout