For detailed troubleshooting, see `references/troubleshooting.md`.
Resources
10Install
npx skillscat add arlenagreer/claude-configuration-docs/skills-rails-dev-environment Install via the SkillsCat registry.
Rails Development Environment Skill
Generates isolated, Dockerized Rails development environments with browser automation and service mocking.
Quick Start
# New Rails project
/rails-dev-env new myapp --profile standard
# Existing project (auto-detects Rails/Ruby versions)
/rails-dev-env setup --profile fullCommands
new - Create New Environment
/rails-dev-env new <project_name> [options]Options:
--profile <minimal|standard|full>- Service profile (default: standard)--rails <version>- Rails version (default: 8.1)--ruby <version>- Ruby version (default: 3.4.1)
โ ๏ธ CRITICAL: Rails 8.1+ requires Ruby 3.4+ due to anonymous rest parameter syntax.
Using Ruby 3.3.x with Rails 8.1.x will cause syntax errors.
setup - Configure Existing Project
/rails-dev-env setup [options]Options:
--profile <minimal|standard|full|custom>- Service profile--services <list>- Custom services (comma-separated)--force- Overwrite existing Docker configuration
validate - Validate Configuration
/rails-dev-env validatestatus - Show Environment Status
/rails-dev-env statusService Profiles
| Profile | Services | Min Memory | Recommended | Use Case |
|---|---|---|---|---|
| minimal | app, postgres, redis | 2 GB | 4 GB | Learning, simple apps |
| standard | minimal + sidekiq, mailpit, playwright, selenium, browsers | 6 GB | 8 GB | Most web applications, E2E testing |
| full | standard + localstack, wiremock, dozzle | 8 GB | 12+ GB | Enterprise, complex integrations |
๐งช E2E Testing Ready: Standard profile now includes full browser automation infrastructure (Playwright, Selenium, Chrome, Firefox) making it fully equipped for end-to-end testing out of the box.
Note: Memory values are Docker Desktop allocation requirements. See
references/profiles.mdfor detailed per-service memory breakdown and optimization tips.
Workflow: New Environment
When user requests a new Rails development environment:
Phase 1: Gather Requirements
Ask user for project details using AskUserQuestion:
questions:
- question: "Which service profile do you need?"
header: "Profile"
options:
- label: "Standard (Recommended)"
description: "Rails, PostgreSQL, Redis, Sidekiq, Mailpit + Playwright/Selenium (E2E ready)"
- label: "Minimal"
description: "Rails, PostgreSQL, Redis only (no E2E testing)"
- label: "Full"
description: "Standard + AWS mocking (LocalStack), API mocking (WireMock), Dozzle"
- label: "Custom"
description: "Select individual services"
- question: "Which Rails version?"
header: "Rails"
options:
- label: "Rails 8.1 (Recommended)"
description: "Latest stable (requires Ruby 3.4+)"
- label: "Rails 8.0"
description: "Propshaft, Import Maps, Solid Queue (Ruby 3.2+)"
- label: "Rails 7.2"
description: "Stable with Hotwire, good gem compatibility"
- label: "Other"
description: "Specify version manually"Phase 2: Analyze Existing Project (if applicable)
If setting up an existing project, run detection:
from scripts.detect_project import analyze_project
analysis = analyze_project(project_path)
# Returns: ProjectAnalysis with rails_version, ruby_version,
# database_adapter, existing_docker, detected_servicesPhase 3: Allocate Ports
from scripts.allocate_ports import allocate_port, PORT_RANGES
ports = {}
for service, (start, end) in PORT_RANGES.items():
ports[service] = allocate_port(
env_name=project_name,
service=service,
start_port=start,
end_port=end
)Port Ranges (Smart allocation prevents conflicts between concurrent environments):
| Service | Range | Notes |
|---|---|---|
| rails | 3000-3099 | Primary application server |
| postgres | 5432-5499 | Database |
| redis | 6379-6399 | Cache/sessions |
| mailpit_web | 8025-8049 | Email preview UI |
| mailpit_smtp | 1025-1049 | SMTP capture |
| playwright_cdp | 9222-9299 | Chrome DevTools Protocol |
| selenium_hub | 4444-4499 | Selenium Grid hub |
| selenium_chrome | 7900-7949 | VNC for headed Chrome |
| selenium_firefox | 7950-7999 | VNC for headed Firefox |
| localstack | 4566-4599 | AWS service emulation |
| wiremock | 8080-8099 | API mocking |
| dozzle | 9999-9999 | Log viewer |
๐ Multi-Environment Support: The port allocation system automatically assigns unique ports to each development environment, allowing you to run multiple projects simultaneously without conflicts.
Phase 4: Generate Configuration Files
from scripts.generate_templates import EnvironmentConfig, generate_all
import secrets
config = EnvironmentConfig(
project_name=project_name,
project_path=project_path,
rails_version=(8, 1, 2),
ruby_version="3.4.1", # CRITICAL: Rails 8.1+ requires Ruby 3.4+
node_version="20",
bundler_version="2.5.0",
profile="standard",
services=["postgres", "redis", "sidekiq", "mailpit"],
ports=ports,
features={"action_cable": True, "active_storage": True},
secret_key_base=secrets.token_hex(32),
generated_at=datetime.now().isoformat(),
skill_version="1.0.0"
)
result = generate_all(config, project_path)Generated Files:
project/
โโโ Dockerfile
โโโ Dockerfile.playwright
โโโ docker-compose.yml
โโโ .env
โโโ .env.template
โโโ bin/
โ โโโ dev-setup.sh
โ โโโ dev-start.sh
โ โโโ dev-stop.sh
โ โโโ dev-status.sh
โ โโโ dev-logs.sh
โ โโโ dev-reset.sh
โ โโโ dev-rollback.sh
โโโ .devcontainer/
โโโ devcontainer.jsonPhase 5: Validate Configuration
from scripts.validate_environment import run_all_validations
report = run_all_validations(project_path)
if not report.all_passed:
# Report issues and fix recommendations
for result in report.results:
if not result.passed:
print(f"Issue: {result.message}")
for fix in result.suggestions:
print(f" Fix: {fix}")Phase 6: Initialize Database with Seeds
CRITICAL: After building the environment, automatically initialize the database using db/seeds.rb. The seeds file should contain BOTH production-critical data AND test/demo data.
# Run database setup and seeding
./bin/dev-setup.sh # Creates and migrates database
docker compose exec app rails db:seedSeeds.rb Best Practice: Structure your seeds.rb to include:
# db/seeds.rb
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# PRODUCTION-CRITICAL DATA (Required for application to function)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
puts "๐ง Loading production-critical data..."
# System roles that the application requires
Role.find_or_create_by!(name: 'admin') { |r| r.permissions = ['all'] }
Role.find_or_create_by!(name: 'user') { |r| r.permissions = ['read', 'write'] }
# Required configuration records
Setting.find_or_create_by!(key: 'app_name') { |s| s.value = 'MyApp' }
# Default categories, statuses, etc.
Status.find_or_create_by!(name: 'active')
Status.find_or_create_by!(name: 'inactive')
puts "โ
Production-critical data loaded"
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# TEST/DEMO DATA (Development and testing convenience)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
if Rails.env.development? || Rails.env.test?
puts "๐งช Loading test/demo data..."
# Demo admin user
admin = User.find_or_create_by!(email: 'admin@example.com') do |u|
u.password = 'password123'
u.role = Role.find_by(name: 'admin')
end
# Sample data for testing
5.times do |i|
User.find_or_create_by!(email: "user#{i}@example.com") do |u|
u.password = 'password123'
u.role = Role.find_by(name: 'user')
end
end
# Add realistic demo data using Faker if available
if defined?(Faker)
10.times do
Project.create!(
name: Faker::App.name,
description: Faker::Lorem.paragraph,
user: User.all.sample
)
end
end
puts "โ
Test/demo data loaded"
endAutomatic Seeding Behavior:
./bin/dev-setup.shnow runsdb:seedautomatically afterdb:migrate- Seeds are idempotent (safe to run multiple times via
find_or_create_by!) - Environment-aware: Test/demo data only loads in development/test
Phase 7: Start Development Server
โก AUTOMATIC SERVER STARTUP: After completing the build, the skill automatically starts the development server.
from scripts.allocate_ports import allocate_port, is_port_available, PORT_RANGES
# Smart port allocation to avoid conflicts with other running dev servers
rails_port = ports.get('rails', 3000)
# Check if allocated port is still available (another server may have started)
if not is_port_available(rails_port):
# Find next available port in range
rails_port = allocate_port(
env_name=project_name,
service='rails',
start_port=PORT_RANGES['rails'][0],
end_port=PORT_RANGES['rails'][1]
)
print(f"โ ๏ธ Port conflict detected. Allocated new port: {rails_port}")
# Start the development server
subprocess.run(['./bin/dev-start.sh'], check=True)๐ PORT ALLOCATION SMART FEATURES (Critical for avoiding conflicts):
- Unique Port Assignment: Each environment gets its own port range allocation
- Conflict Detection: Checks for running servers before starting
- Automatic Re-allocation: Finds next available port if conflict detected
- Port Registry: Maintains registry at
~/.rails-dev-env/port_allocations.json - Multi-Environment Support: Run multiple projects simultaneously without conflicts
# Example: Running multiple projects
# Project A: Rails on 3000, PostgreSQL on 5432
# Project B: Rails on 3001, PostgreSQL on 5433
# Project C: Rails on 3002, PostgreSQL on 5434Server Startup Output:
๐ Starting development server...
๐ Port allocation: Rails=3001, PostgreSQL=5433, Redis=6380
โก Server ready at http://localhost:3001Phase 8: Display Getting Started Guide
After successful generation, show the user:
## โ
Rails Development Environment Created & Running
**Project:** {{ project_name }}
**Profile:** {{ profile }}
**Rails:** {{ rails_version }} | **Ruby:** {{ ruby_version }}
### ๐ Your Server is Already Running!
The development server started automatically after build completion.
**๐ Allocated Ports** (smart allocation avoids conflicts with other running servers):
- Rails: http://localhost:{{ ports.rails }}
{% if has_mailpit %}
- Mailpit: http://localhost:{{ ports.mailpit_web }}
{% endif %}
{% if has_playwright %}
- Playwright CDP: ws://localhost:{{ ports.playwright_cdp }}
{% endif %}
{% if has_selenium %}
- Selenium Hub: http://localhost:{{ ports.selenium }}
{% endif %}
{% if has_dozzle %}
- Logs: http://localhost:{{ ports.dozzle }}
{% endif %}
### ๐งช Database Pre-Populated
Your database has been initialized with:
- โ
Production-critical data (roles, settings, configurations)
- โ
Test/demo data (sample users, demo records)
Demo credentials: `admin@example.com` / `password123`
### ๐งช E2E Testing Ready (Standard+ Profile)
Browser automation is fully configured:
```bash
# Run system tests with Playwright
rails test:system
# Run with headed browser (visible)
HEADED=true rails test:system
# Run with Selenium
SELENIUM=true rails test:systemAvailable Commands
| Command | Description |
|---|---|
./bin/dev-start.sh |
Start all services |
./bin/dev-stop.sh |
Stop all services |
./bin/dev-status.sh |
Show service status & allocated ports |
./bin/dev-logs.sh |
View logs |
./bin/dev-reset.sh |
Reset environment (re-seeds database) |
./bin/dev-test.sh |
Run test suite including E2E tests |
./bin/dev-rollback.sh |
Backup/restore configuration |
---
## Workflow: Setup Existing Project
### Phase 1: Detect Project Configuration
```python
analysis = analyze_project(project_path)
if analysis.rails_version:
info(f"Detected Rails {'.'.join(map(str, analysis.rails_version))}")
if analysis.ruby_version:
info(f"Detected Ruby {analysis.ruby_version}")
if analysis.existing_docker:
warn("Existing Docker configuration found")
# Ask user about overwritePhase 2: Confirm or Customize
If detection succeeds, confirm with user:
- Detected versions
- Recommended profile based on detected services
- Any existing Docker files to backup
Phase 3-6: Same as New Environment
Follow steps from "New Environment" workflow.
Custom Service Selection
For --profile custom, present service picker:
questions:
- question: "Which services do you need?"
header: "Services"
multiSelect: true
options:
- label: "PostgreSQL"
description: "Primary database"
- label: "Redis"
description: "Caching, sessions, Action Cable"
- label: "Sidekiq"
description: "Background job processing"
- label: "Mailpit"
description: "Email testing"
- label: "Browser Automation (Playwright + Selenium)"
description: "Full E2E testing: Chromium, Firefox, WebKit, headed/headless modes"
- label: "LocalStack"
description: "AWS service mocking (S3, SQS, SNS)"
- label: "WireMock"
description: "API mocking"
- label: "Dozzle"
description: "Real-time log viewer"Error Handling
Port Conflicts
if not is_port_available(port):
# Find next available port in range
port = allocate_port(env_name, service, start, end)Existing Configuration
If docker-compose.yml exists:
- Create backup:
docker-compose.yml.backup.{timestamp} - Warn user about overwrite
- Offer to merge or replace
Version Mismatch
If detected version differs from requested:
โ ๏ธ Project uses Ruby 3.2.2 but 3.4.1 requested.
Using detected version for compatibility.Rails 8.1 Ruby Requirement
โ ERROR: Rails 8.1.x requires Ruby 3.4+
Rails 8.1 uses anonymous rest parameter syntax (`**`) which is only
available in Ruby 3.4.0 and later. Ruby 3.3.x will fail with:
syntax error, unexpected tPOW, expecting ')'
def foo(**)
^~
FIX: Update Ruby version to 3.4.1 or use Rails 8.0.xReference Files
The skill uses these reference documents for decision making:
| File | Purpose |
|---|---|
references/rails-ruby-matrix.md |
Version compatibility lookup |
references/service-catalog.md |
Service configuration details |
references/docker-templates.md |
Dockerfile patterns by Rails version |
references/profiles.md |
Profile definitions and resource estimates |
references/troubleshooting.md |
Common issues and solutions |
Scripts API Reference
scripts/allocate_ports.py
allocate_port(env_name, service, start_port, end_port) -> int
release_ports(env_name) -> None
get_allocated_ports(env_name) -> Dict[str, int]
is_port_available(port) -> bool
cleanup_stale_allocations() -> intscripts/detect_project.py
analyze_project(project_path) -> ProjectAnalysis
detect_rails_version(project_path) -> Optional[Tuple[int, int, int]]
detect_ruby_version(project_path) -> Optional[str]
detect_database_config(project_path) -> Dict
detect_services(project_path) -> List[str]scripts/generate_templates.py
generate_all(config: EnvironmentConfig, output_path) -> GenerationResult
create_context(config) -> Dict[str, Any]
render_template(template_name, context) -> strscripts/validate_environment.py
run_all_validations(project_path) -> ValidationReport
validate_compose_syntax(compose_path) -> ValidationResult
validate_ports(ports) -> ValidationResult
test_service_connectivity(service, host, port) -> boolVersion History
| Version | Date | Changes |
|---|---|---|
| 1.1.0 | 2026-02-06 | Major update: Browser automation (Playwright + Selenium) now in Standard profile; automatic db:seed after build; automatic server startup with smart port allocation |
| 1.0.1 | 2026-02-04 | Updated defaults: Ruby 3.4.1, Rails 8.1; added /tmp/pids directory |
| 1.0.0 | 2026-02-03 | Initial release with full profile support |
Troubleshooting Quick Reference
| Issue | Solution |
|---|---|
| Port already in use | Smart allocation auto-assigns next available port; check ./bin/dev-status.sh |
| Database connection refused | Wait for health check or run ./bin/dev-start.sh |
| Database missing seed data | Run docker compose exec app rails db:seed |
| Sidekiq not processing | Check Redis connection, verify queue configuration |
| Playwright tests fail | Ensure PLAYWRIGHT_BROWSER_ENDPOINT is set; check ./bin/dev-status.sh |
| Selenium tests fail | Check SELENIUM_HUB_URL; ensure browsers are running |
| E2E tests timing out | Increase timeout or check browser container health |
| Headed browser not visible | Ensure VNC ports (7900-7999) are accessible |
| LocalStack services unavailable | Check AWS_ENDPOINT_URL points to LocalStack |
| Server didn't auto-start | Check for port conflicts; run ./bin/dev-start.sh manually |
For detailed troubleshooting, see references/troubleshooting.md.