From 204aa1d9ef343fdafffccf9b5644540c404f860c Mon Sep 17 00:00:00 2001 From: Brock Wilcox Date: Sat, 24 Oct 2026 11:21:20 -0400 Subject: [PATCH] Make local development setup smoother - bin/setup: install the bundler version from Gemfile.lock instead of `bundle update --bundler` (which could install a prerelease and rewrite the lockfile); actually run `bundle install` when `bundle check` fails; don't block on a keypress after creating .env, and explain what to check if the database can't be set up. - Add bin/db to run Postgres in Docker via the devcontainer compose service, and document it in README/CONTRIBUTING/.env.example. - bin/start honors PORT (e.g. PORT=3001 bin/start); dev mailer links follow the web server's port. - CI Postgres 12.3 -> 16.13 to match production RDS; update StrongMigrations.target_version to 16.13. - Add benchmark gem to silence the Ruby 3.5 default-gem warning from delayed_job. - Drop obsolete `version:` key from the devcontainer compose file. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01A1Q6b5q6YnqkjpKs7VcK19 --- .devcontainer/docker-compose.yml | 2 - .env.example | 2 + .github/workflows/factory-bot-lint.yml | 2 +- .github/workflows/rspec-system.yml | 2 +- .github/workflows/rspec.yml | 2 +- CLAUDE.md | 3 +- CONTRIBUTING.md | 8 ++-- Gemfile | 2 + Gemfile.lock | 2 + Procfile.dev | 2 +- README.md | 8 ++-- bin/db | 49 ++++++++++++++++++++++++ bin/setup | 21 ++++++---- bin/start | 8 +++- config/environments/development.rb | 5 ++- config/initializers/strong_migrations.rb | 2 +- 16 files changed, 94 insertions(+), 26 deletions(-) create mode 100755 bin/db diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index c9d8bdb5bd..98c812c011 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: app: build: diff --git a/.env.example b/.env.example index fee286d6cc..e3821fd234 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,5 @@ +# Leave blank to connect as your OS user. If you run Postgres with bin/db, +# set both of these to "postgres". PG_USERNAME= PG_PASSWORD= DELAYED_JOB_USERNAME='admin' diff --git a/.github/workflows/factory-bot-lint.yml b/.github/workflows/factory-bot-lint.yml index 21811ff1ab..49bb431d92 100644 --- a/.github/workflows/factory-bot-lint.yml +++ b/.github/workflows/factory-bot-lint.yml @@ -19,7 +19,7 @@ jobs: services: db: - image: postgres:12.3 + image: postgres:16.13 env: POSTGRES_PASSWORD: password ports: diff --git a/.github/workflows/rspec-system.yml b/.github/workflows/rspec-system.yml index 6df173393b..0bb301791c 100644 --- a/.github/workflows/rspec-system.yml +++ b/.github/workflows/rspec-system.yml @@ -18,7 +18,7 @@ jobs: services: db: - image: postgres:12.3 + image: postgres:16.13 env: POSTGRES_PASSWORD: password ports: diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index 177272d45d..72a0ce4cf6 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -18,7 +18,7 @@ jobs: services: db: - image: postgres:12.3 + image: postgres:16.13 env: POSTGRES_PASSWORD: password ports: diff --git a/CLAUDE.md b/CLAUDE.md index e7dc1b76bc..df27db30c7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,8 +10,9 @@ Human Essentials is a Ruby on Rails inventory management system for diaper banks ### Development ```bash +bin/db # Starts Postgres in Docker (user/password: postgres/postgres; also stop|status|logs|psql) bin/setup # First-time setup (installs gems, creates DB, seeds) -bin/start # Starts Rails server (port 3000) + Delayed Job worker +bin/start # Starts Rails server (port 3000, or $PORT) + Delayed Job worker ``` ### Testing diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f9bb52c2a9..1334804bf1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,12 +34,12 @@ You might also want to try VSCode with [this WSL extension](https://marketplace. - Install the version specified in [`.ruby-version`](.ruby-version). - Visit the [Install Ruby on Rails](https://gorails.com/setup/osx/12-monterey) guide by GoRails for Ubuntu, Windows, and macOSX setup. ⚠️ Follow only the Installing Ruby step, as our project setup differs ⚠️ It is highly recommended you use a ruby version manager such as [rbenv](https://github.com/rbenv/rbenv), [asdf](https://asdf-vm.com/), or [rvm](https://rvm.io/). - Verify that your Ruby installation works by running `ruby -v`. -2. Install Postgres - - Follow one of these guides: [MacOSX](https://www.digitalocean.com/community/tutorials/how-to-use-postgresql-with-your-ruby-on-rails-application-on-macos), [Ubuntu](https://www.digitalocean.com/community/tutorials/how-to-use-postgresql-with-your-ruby-on-rails-application-on-ubuntu-18-04). - - Create a `database.yml` file on `config/` directory with your database configurations. You can also copy the existing files called [`database.yml.example`](config/database.yml.example) and [`.env.example`](.env.example) and change the credentials. +2. Set up Postgres + - **With Docker:** after cloning the project (step 3), run `bin/db` to start Postgres in a container (`bin/db stop` stops it), then copy [`.env.example`](.env.example) to `.env` and set `PG_USERNAME=postgres` and `PG_PASSWORD=postgres`. + - **Or install it locally:** follow one of these guides: [MacOSX](https://www.digitalocean.com/community/tutorials/how-to-use-postgresql-with-your-ruby-on-rails-application-on-macos), [Ubuntu](https://www.digitalocean.com/community/tutorials/how-to-use-postgresql-with-your-ruby-on-rails-application-on-ubuntu-18-04). If your database credentials differ from the defaults, copy [`.env.example`](.env.example) to `.env` and set `PG_USERNAME` and `PG_PASSWORD`. 3. Clone the project and switch to its directory 4. Run `bin/setup` -5. Run `bin/start` and visit http://localhost:3000/ to see the human essentials page. +5. Run `bin/start` and visit http://localhost:3000/ to see the human essentials page. To use a different port, run `PORT=3001 bin/start`. 6. Log in as a sample user with the default [credentials](#credentials). ## Credentials diff --git a/Gemfile b/Gemfile index 6077e044cd..882e084d5b 100644 --- a/Gemfile +++ b/Gemfile @@ -84,6 +84,8 @@ gem "bugsnag" gem 'delayed_job_active_record' # UI for showing job status. gem 'delayed_job_web' +# Used by delayed_job; no longer a default gem as of Ruby 3.5. +gem "benchmark" # Sends invitations via e-mail for new users. gem "devise_invitable" # Environment variable and configuration management. diff --git a/Gemfile.lock b/Gemfile.lock index c83ef6b9fd..0fdcc6ba86 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -119,6 +119,7 @@ GEM nokogiri (~> 1, >= 1.10.8) base64 (0.3.0) bcrypt (3.1.22) + benchmark (0.5.0) better_errors (2.10.1) erubi (>= 1.0.0) rack (>= 0.9.0) @@ -779,6 +780,7 @@ DEPENDENCIES awesome_print aws-sdk-s3 azure-storage-blob + benchmark better_errors binding_of_caller bootsnap diff --git a/Procfile.dev b/Procfile.dev index c3527f6e11..adf534c3d7 100644 --- a/Procfile.dev +++ b/Procfile.dev @@ -1,2 +1,2 @@ -web: bundle exec rails s -p 3000 +web: bundle exec rails s -p $PORT worker: bundle exec rails jobs:work diff --git a/README.md b/README.md index 28513f7f7e..f560713b7b 100644 --- a/README.md +++ b/README.md @@ -63,12 +63,12 @@ Thanks for checking us out! Here is a quick-start, and also check out our [Contr - Install the version specified in [`.ruby-version`](.ruby-version). - Visit the [Install Ruby on Rails](https://gorails.com/setup/osx/12-monterey) guide by GoRails for Ubuntu, Windows, and macOS setup. Follow only the Installing Ruby step, as our project setup differs. It is highly recommended you use a Ruby version manager such as [rbenv](https://github.com/rbenv/rbenv), [asdf](https://asdf-vm.com/), or [rvm](https://rvm.io/). - Verify that your Ruby installation works by running `ruby -v`. -2. Install Postgres - - Follow one of these guides: [macOS](https://www.digitalocean.com/community/tutorials/how-to-use-postgresql-with-your-ruby-on-rails-application-on-macos), [Ubuntu](https://www.digitalocean.com/community/tutorials/how-to-use-postgresql-with-your-ruby-on-rails-application-on-ubuntu-18-04). - - Create a `database.yml` file in the `config/` directory with your database configurations. You can also copy the existing files called [`database.yml.example`](config/database.yml.example) and [`.env.example`](.env.example) and change the credentials. +2. Set up Postgres + - **With Docker:** after cloning the project (step 3), run `bin/db` to start Postgres in a container (`bin/db stop` stops it), then copy [`.env.example`](.env.example) to `.env` and set `PG_USERNAME=postgres` and `PG_PASSWORD=postgres`. + - **Or install it locally:** follow one of these guides: [macOS](https://www.digitalocean.com/community/tutorials/how-to-use-postgresql-with-your-ruby-on-rails-application-on-macos), [Ubuntu](https://www.digitalocean.com/community/tutorials/how-to-use-postgresql-with-your-ruby-on-rails-application-on-ubuntu-18-04). If your database credentials differ from the defaults, copy [`.env.example`](.env.example) to `.env` and set `PG_USERNAME` and `PG_PASSWORD`. 3. Clone the project and switch to its directory 4. Run `bin/setup` -5. Run `bin/start` and visit http://localhost:3000/ to see the Human Essentials page. +5. Run `bin/start` and visit http://localhost:3000/ to see the Human Essentials page. To use a different port, run `PORT=3001 bin/start`. 6. Log in as a sample user with the default [credentials](#credentials-for-development-and-staging). ### Cloud Development diff --git a/bin/db b/bin/db new file mode 100755 index 0000000000..94ee752c3b --- /dev/null +++ b/bin/db @@ -0,0 +1,49 @@ +#!/bin/bash +# +# Runs the development Postgres database in Docker, using the postgres service +# from the dev container's compose file. It listens on localhost:5432 with +# username "postgres" and password "postgres" - set PG_USERNAME and PG_PASSWORD +# in .env to match. +# +# Usage: bin/db [up|stop|status|logs|psql] (default: up) + +set -euo pipefail + +cd "$(dirname "$0")/.." + +compose() { + docker compose -f .devcontainer/docker-compose.yml "$@" +} + +case "${1:-up}" in + up) + compose up -d postgres + echo "Waiting for Postgres to accept connections..." + for _ in $(seq 1 30); do + if compose exec -T postgres pg_isready -U postgres > /dev/null 2>&1; then + echo "Postgres is ready on localhost:5432 (username: postgres, password: postgres)" + exit 0 + fi + sleep 1 + done + echo "Postgres did not become ready after 30 seconds - check bin/db logs" >&2 + exit 1 + ;; + stop) + compose stop postgres + ;; + status) + compose ps postgres + ;; + logs) + compose logs -f postgres + ;; + psql) + shift + compose exec postgres psql -U postgres "$@" + ;; + *) + echo "Usage: bin/db [up|stop|status|logs|psql]" >&2 + exit 1 + ;; +esac diff --git a/bin/setup b/bin/setup index 59f42e246b..307fe28c53 100755 --- a/bin/setup +++ b/bin/setup @@ -49,20 +49,27 @@ FileUtils.chdir APP_ROOT do log "== Installing dependencies ==" system! "gem install foreman" - system! "gem install bundler --conservative" - system!("bundle update --bundler --verbose") - system!("bundle check") || system!("bundle install") + # Install the bundler version the lockfile was built with, rather than the + # newest release (which may be a prerelease). + bundler_version = File.read("Gemfile.lock")[/^BUNDLED WITH\n\s+(\S+)/, 1] + system! "gem install bundler -v #{bundler_version} --conservative" + system("bundle check") || system!("bundle install") unless File.exist?('.env') log "== Setting up .env file from .env.example ==" system!('cp .env.example .env') - log "Check .env to see if your database credentials are correct.\nPress Enter to continue...", color: :red - gets + log "Created .env - edit it if your database credentials differ from the defaults (see .env.example)." end log "== Preparing database ==" - log "⚠️ If you use docker to run postgres, make sure your database is running ⚠️" - system! 'bin/rails db:reset' + log "⚠️ If you use docker to run postgres (bin/db), make sure your database is running ⚠️" + system('bin/rails db:reset') || abort(<<~MSG) + + == Could not set up the database == + Check that Postgres is running and that the credentials in .env are correct. + To run Postgres in Docker instead, run bin/db and set PG_USERNAME=postgres + and PG_PASSWORD=postgres in .env, then re-run bin/setup. + MSG system! 'bin/rails db:test:prepare' log "== Removing old logs, tempfiles, and jobs ==" diff --git a/bin/start b/bin/start index 9fc1bac147..b82ecd4502 100755 --- a/bin/start +++ b/bin/start @@ -1,3 +1,9 @@ #!/bin/bash -bundle exec foreman start -f Procfile.dev +# Set PORT to run the web server somewhere other than 3000, e.g. PORT=3001 bin/start +port="${PORT:-3000}" +# Foreman gives each process its own PORT, so pass the web server's port along +# separately for links built outside a request (e.g. emails sent by jobs). +export WEB_PORT="$port" + +bundle exec foreman start -f Procfile.dev -p "$port" diff --git a/config/environments/development.rb b/config/environments/development.rb index 20bcb38796..284a074e5b 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -34,8 +34,9 @@ # Show full error reports. config.consider_all_requests_local = true - config.action_mailer.default_url_options = { host: "localhost:3000" } - config.action_mailer.asset_host = "http://localhost:3000" + app_host = ENV["APP_HOST"].presence || "localhost:#{ENV.fetch("WEB_PORT", 3000)}" + config.action_mailer.default_url_options = { host: app_host } + config.action_mailer.asset_host = "http://#{app_host}" # Enable/disable caching. By default caching is disabled. if Rails.root.join("tmp/caching-dev.txt").exist? diff --git a/config/initializers/strong_migrations.rb b/config/initializers/strong_migrations.rb index b1dbab2c72..dfe1fefdb7 100644 --- a/config/initializers/strong_migrations.rb +++ b/config/initializers/strong_migrations.rb @@ -12,7 +12,7 @@ # Set the version of the production database # so the right checks are run in development -StrongMigrations.target_version = 16.3 +StrongMigrations.target_version = 16.13 # Add custom checks # StrongMigrations.add_check do |method, args|