Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
994ff45
Re-introduce system executable
stevepolitodesign Dec 11, 2025
71a76db
Optimize for Heroku (#1260)
stevepolitodesign Dec 11, 2025
b3cc02c
Configure test suite (#1262)
stevepolitodesign Dec 11, 2025
5131b8b
Configure Sidekiq (#1264)
stevepolitodesign Dec 11, 2025
4c8be42
Update layout (#1265)
stevepolitodesign Dec 11, 2025
e72a921
Introduce accessibility tooling (#1266)
stevepolitodesign Dec 11, 2025
03dad47
Configure mailer interceptor (#1267)
stevepolitodesign Dec 11, 2025
7498352
Configure Inline SVG (#1268)
stevepolitodesign Dec 11, 2025
806cde8
Configure development environment (#1269)
stevepolitodesign Dec 11, 2025
f154989
Configure production environment and set application-wide settings (#…
stevepolitodesign Dec 12, 2025
6e1224b
Update rdoc (#1271)
stevepolitodesign Dec 12, 2025
2ac439f
Introduce Ralph
laicuRoot Dec 12, 2025
3991f88
Introduce strong_migrations
laicuRoot Dec 12, 2025
9caea1a
Fix CI label (#1275)
stevepolitodesign Dec 12, 2025
c4eeb8d
Improve CI script and fix broken layout (#1276)
stevepolitodesign Dec 12, 2025
ef2eab9
Introduce `suspenders -v` and `suspenders new app_name` (#1273)
laicuRoot Dec 12, 2025
a76c802
Update README.md, FEATURES.md and generated README.md (#1277)
stevepolitodesign Dec 12, 2025
e65af5f
Document GitHub Actions and Heroku (#1278)
stevepolitodesign Dec 12, 2025
60c1366
Fix `Procfile.dev` (#1279)
stevepolitodesign Dec 12, 2025
c9b95bd
Fix generated CI scipt (#1280)
stevepolitodesign Dec 12, 2025
d6e5a02
Ignore `/spec/examples.txt` (#1281)
stevepolitodesign Dec 12, 2025
a057bd6
Configure test environment (#1282)
stevepolitodesign Dec 12, 2025
e3daa1b
Fix executable (#1283)
stevepolitodesign Dec 12, 2025
3473218
Improve local development (#1284)
stevepolitodesign Dec 17, 2025
f6edd76
Fix application layout (#1285)
stevepolitodesign Dec 17, 2025
2ac4384
Update documentation (#1286)
stevepolitodesign Dec 19, 2025
0c087e8
Improve QA experience (#1287)
stevepolitodesign Dec 19, 2025
4176366
Introduce `development:db:seed` and `development:db:seed:replant` tas…
stevepolitodesign Dec 19, 2025
4b4fac5
Prepare for release (#1289)
stevepolitodesign Dec 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 90 additions & 18 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,100 @@ on:
pull_request:

jobs:
lint:
build:
runs-on: ubuntu-latest
name: Ruby ${{ matrix.ruby }}
strategy:
matrix:
ruby:
- '3.4.7'

steps:
- uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- name: Run the default task
run: bundle exec rake

- name: Lint
run: bin/rails standard

test:
test-template:
runs-on: ubuntu-latest

services:
postgres:
image: postgres
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: --health-cmd="pg_isready" --health-interval=10s --health-timeout=5s --health-retries=3
redis:
image: valkey/valkey:8
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5

steps:
- uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true

- name: Run tests
run: bin/rails test
- name: Checkout template
uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.4.7'
bundler-cache: false
- name: Install Rails
run: gem install rails
- name: Install dependencies
run: bundle install
- name: Install Suspenders
run: bundle exec rake install
- name: Generate new Rails app with template
run: |
cd /tmp
suspenders new test_app
- name: Set up generated app
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432
working-directory: /tmp/test_app
run: |
bundle install
bin/setup --skip-server
bin/rails db:migrate
bundle add high_voltage
mkdir app/views/pages
touch app/views/pages/home.html.erb
echo '<h1>Hello World!</h1>' >> app/views/pages/home.html.erb
touch spec/system/demo_system_spec.rb
cat << 'EOF' >> spec/system/demo_system_spec.rb
require "rails_helper"

RSpec.describe "Static page", type: :system do
it "passes" do
visit "/pages/home"

expect(page).to have_text("Hello World!")
end
end
EOF
- name: Run tests in generated app
env:
RAILS_ENV: test
DATABASE_URL: postgres://postgres:postgres@localhost:5432
working-directory: /tmp/test_app
run: |
bin/rails db:setup
bin/rails spec
Comment thread
stevepolitodesign marked this conversation as resolved.
- name: Verify app can start
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432
REDIS_URL: redis://localhost:6379/0
working-directory: /tmp/test_app
run: |
timeout 10 bin/dev > /dev/null 2>&1 &
sleep 5
curl -f http://localhost:3000 || exit 1
15 changes: 8 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/.bundle/
/.yardoc
/_yardoc/
/coverage/
/doc/
/log/*.log
/pkg/
/spec/reports/
/tmp/
/test/dummy/db/*.sqlite3
/test/dummy/db/*.sqlite3-*
/test/dummy/log/*.log
/test/dummy/storage/
/test/dummy/tmp/
node_modules

# rspec failure tracking
.rspec_status
/qa/
3 changes: 3 additions & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
--format documentation
--color
--require spec_helper
8 changes: 3 additions & 5 deletions .standard.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
ruby_version: 3.0.5
ignore:
- "templates/partials/db_optimizations_configuration.rb"
- "templates/partials/pull_requests_config.rb"
- "templates/partials/email_smtp.rb"
# For available configuration options, see:
# https://github.com/standardrb/standard
ruby_version: 3.2
31 changes: 16 additions & 15 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,10 @@ Run the setup script.
./bin/setup
```

Make sure the tests pass:
Make sure everything passes:

```
bin/rails test
```

Make sure there are no linting violations:

```
bin/rails standard
bundle exec rake
```

Make your change, with new passing tests.
Expand All @@ -46,16 +40,23 @@ This is a time for discussion and improvements,
and making the necessary changes will be required before we can
merge the contribution.

## Testing Generators
## Testing the executable Locally

To install this gem onto your local machine, run `bundle exec rake install`.
From there, you can run `suspenders new <app_name>` to test the current code.

In an effort to help distinguish code generated by `rails new` from code
generated by the application template, you can run `bin/qa`.

From there you can `cd qa` and run `git diff` to see what changed.

There is a smaller dummy application at `test/dummy`. This application is used
as a mounting point for the engine, to make testing the engine extremely simple.
This can be useful for testing Suspenders after a new release of Rails.

There are a number of [assertions][] and [helpers][] that make testing
generators easier.
## Documenting changes to generated application

[assertions]: https://api.rubyonrails.org/classes/Rails/Generators/Testing/Assertions.html
[helpers]: https://api.rubyonrails.org/classes/Rails/Generators/Testing/Behavior.html
Be sure to update `FEATURES.md` and the contents of `update_readme` within
`web.rb` anytime you add, update or remove a feature to the generated
application.

## Publishing to RubyGems

Expand Down
125 changes: 51 additions & 74 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,75 +2,82 @@

## Local Development

### Strong Migrations

Uses [Strong Migrations][] to catch unsafe migrations in development.

[Strong Migrations]: https://github.com/ankane/strong_migrations

### Seed Data

- Use `db/seeds.rb` to create records that need to exist in all environments.
- Use `lib/tasks/dev.rake` to create records that only need to exist in development.
Follows [our guidance][seed-data-guide] for managing seed data. Use
`db/seeds.rb` for data required in **all** environments, and
`development:db:seed` for data specific to development environments.

Place idempotent seed data in `Development::Seeder`.

To load development seed data:

```bash
bin/rails development:db:seed
```

To reset your database and reload seed data:

```bash
bin/rails development:db:seed:replant
```

The `replant` command truncates all tables and reloads the seed data, providing
a clean slate for development.

Running `bin/setup` will run `dev:prime`.
[seed-data-guide]: https://github.com/thoughtbot/guides/blob/main/rails/how-to/seed-data.md

### Tasks
## Environment Variables

- Use `bin/rails suspenders:db:migrate` to run [database migrations][]. This script ensures they are [reversible][].
- Use `bin/rails suspenders:cleanup:organize_gemfile` to automatically organize the project's Gemfile.
- Use `bin/rails default` to run the default Rake task. This will do the following:
- Run the test suite.
- Run a Ruby and ERB linter.
- Scan the Ruby codebase for any dependency vulnerabilities.
The following environment variables are available in `production`:

[database migrations]: https://edgeguides.rubyonrails.org/active_record_migrations.html#running-migrations
[reversible]: https://edgeguides.rubyonrails.org/active_record_migrations.html#making-the-irreversible-possible
- `APPLICATION_HOST` - The domain where your application is hosted (required)
- `ASSET_HOST` - CDN or asset host URL (optional)
- `RAILS_MASTER_KEY` - Used for decrypting credentials (required)

## Configuration

### All Environments

- Enables [strict_loading_by_default][].
- Sets [strict_loading_mode][] to `:n_plus_one`.
- Enables [require_master_key][].

[strict_loading_by_default]: https://guides.rubyonrails.org/configuring.html#config-active-record-strict-loading-by-default
[strict_loading_mode]: https://guides.rubyonrails.org/configuring.html#config-active-record-strict-loading-mode
[require_master_key]: https://guides.rubyonrails.org/configuring.html#config-require-master-key

### Test

- Enables [raise_on_missing_translations][].
- Disables [action_dispatch.show_exceptions][].
- Sets [action_dispatch.show_exceptions][] to `:none`.

[raise_on_missing_translations]: https://guides.rubyonrails.org/configuring.html#config-i18n-raise-on-missing-translations
[action_dispatch.show_exceptions]: https://edgeguides.rubyonrails.org/configuring.html#config-action-dispatch-show-exceptions

### Development

- Enables [raise_on_missing_translations][].
- Enables [annotate_rendered_view_with_filenames][].
- Enables [i18n_customize_full_message][].
- Enables [query_log_tags_enabled][].
- Enables [apply_rubocop_autocorrect_after_generate!][].

[raise_on_missing_translations]: https://guides.rubyonrails.org/configuring.html#config-i18n-raise-on-missing-translations
[annotate_rendered_view_with_filenames]: https://guides.rubyonrails.org/configuring.html#config-action-view-annotate-rendered-view-with-filenames
[i18n_customize_full_message]: https://guides.rubyonrails.org/configuring.html#config-active-model-i18n-customize-full-message
[query_log_tags_enabled]: https://guides.rubyonrails.org/configuring.html#config-active-record-query-log-tags-enabled
[apply_rubocop_autocorrect_after_generate!]: https://guides.rubyonrails.org/configuring.html#configuring-generators

### Production

- Enables [require_master_key][].
- Enables [sandbox_by_default][].
- Sets [action_on_strict_loading_violation][] to `:log`.

[require_master_key]: https://guides.rubyonrails.org/configuring.html#config-require-master-key

### Linting

- Uses [@thoughtbot/eslint-config][] for JavaScript linting.
- Uses [@thoughtbot/stylelint-config][] for CSS linting.
- Uses [prettier][] for additional linting.
- Uses [better_html][], [erb_lint][], and [erblint-github][] for ERB linting.
- Uses [standard][] for Ruby linting.

**Available Commands**

- Run `yarn lint` to lint front-end code.
- Run `yarn fix:prettier` to automatically fix prettier violations.
- Run `bin/rails standard` to lint ERB and Ruby code.
- Run `bundle exec standardrb --fix` to fix standard violations.

[@thoughtbot/eslint-config]: https://github.com/thoughtbot/eslint-config
[@thoughtbot/stylelint-config]: https://github.com/thoughtbot/stylelint-config
[prettier]: https://prettier.io
[better_html]: https://github.com/Shopify/better-html
[erb_lint]: https://github.com/Shopify/erb-lint
[erblint-github]: https://github.com/github/erblint-github
[standard]: https://github.com/standardrb/standard
[sandbox_by_default]: https://guides.rubyonrails.org/configuring.html#config-sandbox-by-default
[action_on_strict_loading_violation]: https://guides.rubyonrails.org/configuring.html#config-active-record-action-on-strict-loading-violation

## Testing

Expand Down Expand Up @@ -122,13 +129,6 @@ practices.
[capybara_accessibility_audit]: https://github.com/thoughtbot/capybara_accessibility_audit
[capybara_accessible_selectors]: https://github.com/citizensadvice/capybara_accessible_selectors

## Advisories

Uses [bundler-audit][] to update the local security database and show
any relevant issues with the app's dependencies via a Rake task.

[bundler-audit]: https://github.com/rubysec/bundler-audit

## Mailers

[Intercept][] emails in non-production environments by setting `INTERCEPTOR_ADDRESSES`.
Expand All @@ -139,7 +139,7 @@ INTERCEPTOR_ADDRESSES="user_1@example.com,user_2@example.com" bin/rails s

Configuration can be found at `config/initializers/email_interceptor.rb`.

Interceptor can be found at `app/mailers/email_interceptor.rb`.
Interceptor can be found at `lib/email_interceptor.rb`.

[Intercept]: https://guides.rubyonrails.org/action_mailer_basics.html#intercepting-emails

Expand All @@ -155,29 +155,6 @@ Configures the `test` environment to use the [inline][] adapter.

## Layout and Assets

### Stylesheets

- Uses [PostCSS][] via [cssbundling-rails][].
- Uses [modern-normalize][] to normalize browsers' default style.

Configuration can be found at `postcss.config.js`.

Adds the following stylesheet structure.

```
app/assets/stylesheets/base.css
app/assets/stylesheets/components.css
app/assets/stylesheets/utilities.css
```

Adds `app/assets/static` so that [postcss-url][] has a directory to copy
assets to.

[PostCSS]: https://postcss.org
[cssbundling-rails]: https://github.com/rails/cssbundling-rails
[modern-normalize]: https://github.com/sindresorhus/modern-normalize
[postcss-url]: https://github.com/postcss/postcss-url

### Inline SVG

Uses [inline_svg][] for embedding SVG documents into views.
Expand All @@ -189,8 +166,8 @@ Configuration can be found at `config/initializers/inline_svg.rb`
### Layout

- A [partial][] for [flash messages][] is located in `app/views/application/_flashes.html.erb`.
- A [partial][] for form errors is located in `app/views/application/_form_errors.html.erb`.
- Sets [lang][] attribute on `<html>` element to `en` via `I18n.local`.
- Dynamically sets `<title>` via the [title][] gem.
- Disables Turbo's [Prefetch][] in an effort to reduce unnecessary network requests.

[partial]: https://guides.rubyonrails.org/layouts_and_rendering.html#using-partials
Expand Down
Loading