arlenagreer

Rails Development Environment Skill

For detailed troubleshooting, see `references/troubleshooting.md`.

arlenagreer 4 Updated 3mo ago

Resources

10
GitHub

Install

npx skillscat add arlenagreer/claude-configuration-docs/skills-rails-dev-environment

Install via the SkillsCat registry.

SKILL.md

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 full

Commands

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 validate

status - Show Environment Status

/rails-dev-env status

Service 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.md for 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_services

Phase 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.json

Phase 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:seed

Seeds.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"
end

Automatic Seeding Behavior:

  • ./bin/dev-setup.sh now runs db:seed automatically after db: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):

  1. Unique Port Assignment: Each environment gets its own port range allocation
  2. Conflict Detection: Checks for running servers before starting
  3. Automatic Re-allocation: Finds next available port if conflict detected
  4. Port Registry: Maintains registry at ~/.rails-dev-env/port_allocations.json
  5. 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 5434

Server Startup Output:

๐Ÿš€ Starting development server...
๐Ÿ“ Port allocation: Rails=3001, PostgreSQL=5433, Redis=6380
โšก Server ready at http://localhost:3001

Phase 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:system

Available 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 overwrite

Phase 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:

  1. Create backup: docker-compose.yml.backup.{timestamp}
  2. Warn user about overwrite
  3. 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.x

Reference 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() -> int

scripts/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) -> str

scripts/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) -> bool

Version 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.