From stevehobbsdev
Generate a new Ruby on Rails application from scratch using `rails new` with all key options configured, Rails best practices applied, and a working VS Code Dev Container setup included. Use this skill whenever the user asks to create, scaffold, bootstrap, initialise, or generate a new Rails app or Rails project, even if they don't say "rails new" explicitly. Also use when they ask for a "Rails starter", "Rails template", or want to know how to set up a new Rails application.
How this skill is triggered — by the user, by Claude, or both
Slash command
/stevehobbsdev:new-rails-appThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill creates a complete, best-practice Rails 8 application with Ruby 4,
This skill creates a complete, best-practice Rails 8 application with Ruby 4,
full rails new option coverage, a working welcome page, and a VS Code Dev
Container configuration.
Ask the user for:
my_app (snake_case, no spaces)If the user hasn't specified, default to: Sqlite3 + Tailwind + ESBuild, full-stack (not API-only).
# Ensure Ruby 4 is active (via rbenv, asdf, or mise)
ruby -v # should be 4.0.x
# Install Rails 8 (latest)
gem install rails
# Verify
rails -v # should be 8.1.x or later
Ensure the default package manager for JavaScript is npm across the repository.
rails newUse the full command below, substituting APP_NAME and adjusting the
--database, --css, and --javascript flags based on user choices.
rails new APP_NAME \
--database=postgresql \
--css=tailwind \
--javascript=importmap \
--devcontainer \
--asset-pipeline=propshaft \
--skip-test \
--no-skip-rubocop \
--no-skip-brakeman \
--no-skip-ci \
--no-skip-kamal
rails new APP_NAME \
--api \
--database=postgresql \
--devcontainer \
--skip-test \
--no-skip-rubocop \
--no-skip-brakeman \
--no-skip-ci \
--no-skip-kamal
rails new APP_NAME \
--database=sqlite3 \
--css=tailwind \
--javascript=importmap \
--devcontainer \
--asset-pipeline=propshaft \
--skip-test \
--no-skip-rubocop \
--no-skip-brakeman \
--no-skip-ci
| Flag | Purpose |
|---|---|
--database=postgresql | Configure ActiveRecord for PostgreSQL |
--css=tailwind | Set up Tailwind CSS via PostCSS |
--javascript=importmap | Use importmap (no Node/npm required) |
--devcontainer | Generate .devcontainer/ for VS Code (Rails 7.2+) |
--asset-pipeline=propshaft | Use Propshaft (modern, replaces Sprockets) |
--skip-test | Skip MiniTest (see Step 5 for RSpec setup) |
--no-skip-rubocop | Include RuboCop for linting |
--no-skip-brakeman | Include Brakeman for security scanning |
--no-skip-ci | Generate GitHub Actions CI workflow |
--no-skip-kamal | Include Kamal for deployment |
--api | API-only mode (no views/assets) |
Rails shows its default welcome page at http://localhost:3000 when no root
route is defined. This is the standard behaviour — no extra steps needed.
To confirm it works:
cd APP_NAME
bin/rails db:create # if using PostgreSQL
bin/rails server
Open http://localhost:3000 — you should see the Rails welcome screen.
Note: The welcome page only appears when
config/routes.rbhas no root route. Once you addroot "pages#home"or similar, define that controller and view before visiting/.
Rails 8 generates a .devcontainer/ folder automatically when you pass
--devcontainer. The generated folder contains:
.devcontainer/
├── devcontainer.json # VS Code dev container configuration
├── Dockerfile # Ruby 4 base image
└── compose.yaml # Docker Compose (app + db + selenium)
devcontainer.jsonThe generated file should look similar to this. Review and adjust as needed:
// .devcontainer/devcontainer.json
{
"name": "APP_NAME",
"dockerComposeFile": "compose.yaml",
"service": "rails-app",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/rails/devcontainer/features/activestorage": {},
"ghcr.io/rails/devcontainer/features/sqlite3": {}
},
"containerEnv": {
"CAPYBARA_SERVER_PORT": "45678",
"SELENIUM_HOST": "selenium"
},
"forwardPorts": [3000],
"postCreateCommand": "bin/setup",
"customizations": {
"vscode": {
"extensions": [
"Shopify.ruby-lsp",
"misogi.ruby-rubocop",
"bradlc.vscode-tailwindcss",
"esbenp.prettier-vscode"
]
}
}
}
Dockerfile in .devcontainer/Ensure the Ruby version matches 4.0:
# .devcontainer/Dockerfile
ARG RUBY_VERSION=4.0
FROM ghcr.io/rails/devcontainer/images/ruby:$RUBY_VERSION
Cmd/Ctrl+Shift+P → Dev Containers: Reopen in Container)bin/setup to runhttp://localhost:3000 in your browserRequirements: Docker Desktop (or OrbStack/Colima) and the Dev Containers extension must be installed.
--skip-test gap)# Add to Gemfile (test/development group)
bundle add rspec-rails --group development,test
bundle add factory_bot_rails --group development,test
bundle add faker --group development,test
# Install
bin/rails generate rspec:install
.ruby-versionEnsure the file contains:
4.0
Rails generates this automatically; verify it matches your Ruby version.
database.yml for PostgreSQL in ProductionThe generated config/database.yml uses sensible defaults. For Dev Container
use, verify the host matches the compose service name:
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
host: <%= ENV.fetch("DB_HOST", "db") %>
username: postgres
password: postgres
development:
<<: *default
database: APP_NAME_development
test:
<<: *default
database: APP_NAME_test
Ruby 4 raises FrozenError for mutated string literals without a magic
comment. Add to all .rb files, or configure RuboCop to enforce it:
# frozen_string_literal: true
Add to .rubocop.yml:
Style/FrozenStringLiteralComment:
Enabled: true
EnforcedStyle: always
###Other necessary RuboCop configurations
(If not already specified, don't duplicate rules)
Ensure rubocop-rspec is also installed and specified in the Gemfile under the test group.
Also ensure TargetRubyVersion points to the same Ruby version we're using for the project.
plugins: rubocop-rspec
AllCops:
TargetRubyVersion: 3.4
# RuboCop has a bunch of cops enabled by default. This setting tells RuboCop
# to ignore them, so only the ones explicitly set in this file are enabled.
DisabledByDefault: true
Exclude:
- "**/templates/**/*"
- "**/vendor/**/*"
- "actionpack/lib/action_dispatch/journey/parser.rb"
SuggestExtensions: false
# Prefer &&/|| over and/or.
Style/AndOr:
Enabled: true
# Align `when` with `case`.
Layout/CaseIndentation:
Enabled: true
# Align comments with method definitions.
Layout/CommentIndentation:
Enabled: true
Layout/ElseAlignment:
Enabled: true
Layout/EmptyLineAfterMagicComment:
Enabled: true
# In a regular class definition, no empty lines around the body.
Layout/EmptyLinesAroundClassBody:
Enabled: true
# In a regular method definition, no empty lines around the body.
Layout/EmptyLinesAroundMethodBody:
Enabled: true
# In a regular module definition, no empty lines around the body.
Layout/EmptyLinesAroundModuleBody:
Enabled: true
Layout/FirstArgumentIndentation:
Enabled: true
# Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
Style/HashSyntax:
Enabled: true
EnforcedShorthandSyntax: always
# Method definitions after `private` or `protected` isolated calls need one
# extra level of indentation.
Layout/IndentationConsistency:
Enabled: true
EnforcedStyle: indented_internal_methods
# Two spaces, no tabs (for indentation).
Layout/IndentationWidth:
Enabled: true
Layout/LeadingCommentSpace:
Enabled: true
Layout/SpaceAfterColon:
Enabled: true
Layout/SpaceAfterComma:
Enabled: true
Layout/SpaceAroundEqualsInParameterDefault:
Enabled: true
Layout/SpaceAroundKeyword:
Enabled: true
Layout/SpaceAroundOperators:
Enabled: true
Layout/SpaceBeforeComma:
Enabled: true
Layout/SpaceBeforeFirstArg:
Enabled: true
Style/DefWithParentheses:
Enabled: true
# Defining a method with parameters needs parentheses.
Style/MethodDefParentheses:
Enabled: true
Style/FrozenStringLiteralComment:
Enabled: false
EnforcedStyle: always
# Use `foo {}` not `foo{}`.
Layout/SpaceBeforeBlockBraces:
Enabled: true
# Use `foo { bar }` not `foo {bar}`.
Layout/SpaceInsideBlockBraces:
Enabled: true
# Use `{ a: 1 }` not `{a:1}`.
Layout/SpaceInsideHashLiteralBraces:
Enabled: true
Layout/SpaceInsideParens:
Enabled: true
# Check quotes usage according to lint rule below.
Style/StringLiterals:
Enabled: true
EnforcedStyle: single_quotes
# Detect hard tabs, no hard tabs.
Layout/IndentationStyle:
Enabled: true
# Blank lines should not have any spaces.
Layout/TrailingEmptyLines:
Enabled: true
# No trailing whitespace.
Layout/TrailingWhitespace:
Enabled: false
# Use quotes for string literals when they are enough.
Style/RedundantPercentQ:
Enabled: true
# Align `end` with the matching keyword or starting expression except for
# assignments, where it should be aligned with the LHS.
Layout/EndAlignment:
Enabled: true
EnforcedStyleAlignWith: variable
AutoCorrect: true
# Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
Lint/RequireParentheses:
Enabled: true
Style/RedundantReturn:
Enabled: true
AllowMultipleReturnValues: true
Style/Semicolon:
Enabled: true
AllowAsExpressionSeparator: true
Add a makefile that contains common tasks:
make lint - runs RuboCop (auto-corrects errors) and Brakeman
make run - runs bin/dev
make test - runs the RSpec tests
Never commit .env files with secrets. Use Rails encrypted credentials:
bin/rails credentials:edit
Store secrets as:
database:
password: your_password
secret_key_base: your_generated_key
bin/rubocop # linting
bin/brakeman # security scan
bin/rails db:create db:migrate
bin/rails server
After generating, offer to help with any of these:
bin/rails generate scaffold ModelName field:type …has_secure_passwordbin/kamal init and configure config/deploy.ymlPostgreSQL connection refused in Dev Container
Check config/database.yml — host: must match the compose service name (default: db). Do not use localhost.
Port 3000 not forwarding
Ensure 3000 is in forwardPorts in devcontainer.json and that Puma binds to 0.0.0.0:
bin/rails server -b 0.0.0.0
Or add to config/puma.rb: bind "tcp://0.0.0.0:3000"
rails new fails with Ruby version error
Rails 8.1 requires Ruby 3.2+. Ruby 4.0 is fully supported. Run ruby -v inside
the Dev Container to confirm the correct version is active.
Welcome page not showing after adding a route If you defined a root route but haven't created the controller/view yet, Rails will error. Either remove the root route temporarily or generate the controller:
bin/rails generate controller Pages home
Then set root "pages#home" in config/routes.rb.
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub stevehobbsdev/claude-skills --plugin stevehobbsdev