Resources

Download Source Code

Summary

# Terminal
bin/rails db:system:change --to=postgresql
docker compose up
bin/rails g model user name email
bin/rails g model car manufacture car_model --database cars
bin/rails g active_record:multi_db

# docker-compose.yml
version: '2'

services:
  postgresql-primary:
    image: docker.io/bitnami/postgresql:14
    ports:
      - '5432:5432'
    volumes:
      - 'postgresql_primary_data:/bitnami/postgresql'
    environment:
      - POSTGRESQL_REPLICATION_MODE=master
      - POSTGRESQL_REPLICATION_USER=repl_user
      - POSTGRESQL_REPLICATION_PASSWORD=repl_password
      - POSTGRESQL_USERNAME=postgres
      - POSTGRESQL_PASSWORD=postgres
      - ALLOW_EMPTY_PASSWORD=yes
  postgresql-replica:
    image: docker.io/bitnami/postgresql:14
    ports:
      - '5433:5432'
    depends_on:
      - postgresql-primary
    volumes:
      - 'postgresql_replica_data:/bitnami/postgresql'
    environment:
      - POSTGRESQL_REPLICATION_MODE=slave
      - POSTGRESQL_REPLICATION_USER=repl_user
      - POSTGRESQL_REPLICATION_PASSWORD=repl_password
      - POSTGRESQL_MASTER_HOST=postgresql-primary
      - POSTGRESQL_USERNAME=postgres
      - POSTGRESQL_PASSWORD=postgres
      - POSTGRESQL_MASTER_PORT_NUMBER=5432
      - ALLOW_EMPTY_PASSWORD=yes

volumes:
  postgresql_primary_data:
    driver: local
  postgresql_replica_data:
    driver: local

# config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  primary:
    <<: *default
    database: template_development
    username: postgres
    password: postgres
    host: localhost
    port: 5432
  primary_replica:
    <<: *default
    database: template_development
    username: postgres
    password: postgres
    host: localhost
    port: 5433
    replica: true
  cars:
    <<: *default
    database: car_development
    username: postgres
    password: postgres
    host: localhost
    port: 5432
    migrations_paths: db/cars_migrate
  cars_replica:
    <<: *default
    database: car_development
    username: postgres
    password: postgres
    host: localhost
    port: 5433
    replica: true

test:
  <<: *default
  database: template_test

production:
  <<: *default
  database: template_production
  username: template
  password: <%= ENV["TEMPLATE_DATABASE_PASSWORD"] %>

# models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  primary_abstract_class
  connects_to database: { writing: :primary, reading: :primary_replica }
end

# config/initializers/multi_db.rb
Rails.application.configure do
  config.active_record.database_selector = { delay: 2.seconds }
  config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
  config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
end

# models/cars_record.rb
class CarsRecord < ApplicationRecord
  self.abstract_class = true

  connects_to database: { writing: :cars, reading: :cars_replica }
end

# models/car.rb
class Car < CarsRecord
end

# bin/rails -T | grep db
rails db:create                          # Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config). Without RAILS_ENV or when RAILS_ENV is development, it defaults to creating the development and test databases, except when DATABASE_URL is present
rails db:create:cars                     # Create cars database for current environment
rails db:create:primary                  # Create primary database for current environment
rails db:drop                            # Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config). Without RAILS_ENV or when RAILS_ENV is development, it defaults to dropping the development and test databases, except when DATABASE_URL is present
rails db:drop:cars                       # Drop cars database for current environment
rails db:drop:primary                    # Drop primary database for current environment
rails db:encryption:init                 # Generate a set of keys for configuring Active Record encryption in a given environment
rails db:environment:set                 # Set the environment value for the database
rails db:fixtures:load                   # Loads fixtures into the current environment's database
rails db:migrate                         # Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)
rails db:migrate:cars                    # Migrate cars database for current environment
rails db:migrate:down                    # Runs the "down" for a given migration VERSION
rails db:migrate:primary                 # Migrate primary database for current environment
rails db:migrate:redo                    # Rolls back the database one migration and re-migrates up (options: STEP=x, VERSION=x)
rails db:migrate:redo:cars               # Rolls back cars database one migration and re-migrates up (options: STEP=x, VERSION=x)
rails db:migrate:redo:primary            # Rolls back primary database one migration and re-migrates up (options: STEP=x, VERSION=x)
rails db:migrate:status                  # Display status of migrations
rails db:migrate:status:cars             # Display status of migrations for cars database
rails db:migrate:status:primary          # Display status of migrations for primary database
rails db:migrate:up                      # Runs the "up" for a given migration VERSION
rails db:prepare                         # Runs setup if database does not exist, or runs migrations if it does
rails db:reset                           # Drops and recreates all databases from their schema for the current environment and loads the seeds
rails db:reset:cars                      # Drops and recreates the cars database from its schema for the current environment and loads the seeds
rails db:reset:primary                   # Drops and recreates the primary database from its schema for the current environment and loads the seeds
rails db:rollback                        # Rolls the schema back to the previous version (specify steps w/ STEP=n)
rails db:rollback:cars                   # Rollback cars database for current environment (specify steps w/ STEP=n)
rails db:rollback:primary                # Rollback primary database for current environment (specify steps w/ STEP=n)
rails db:schema:cache:clear              # Clears a db/schema_cache.yml file
rails db:schema:cache:dump               # Creates a db/schema_cache.yml file
rails db:schema:dump                     # Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`)
rails db:schema:dump:cars                # Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) for cars database
rails db:schema:dump:primary             # Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) for primary database
rails db:schema:load                     # Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) into the database
rails db:schema:load:cars                # Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) into the cars database
rails db:schema:load:primary             # Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) into the primary database
rails db:seed                            # Loads the seed data from db/seeds.rb
rails db:seed:replant                    # Truncates tables of each database for current environment and loads the seeds
rails db:setup                           # Creates all databases, loads all schemas, and initializes with the seed data (use db:reset to also drop all databases first)
rails db:setup:cars                      # Creates the cars database, loads the schema, and initializes with the seed data (use db:reset:cars to also drop the database first)
rails db:setup:primary                   # Creates the primary database, loads the schema, and initializes with the seed data (use db:reset:primary to also drop the database first)
rails db:version                         # Retrieves the current schema version number
rails test:db                            # Run tests quickly, but also reset db