Skip to content

Instantly share code, notes, and snippets.

@nauman
Last active November 13, 2025 14:17
Show Gist options
  • Select an option

  • Save nauman/8557ce551d6910361c8f889a10c82fee to your computer and use it in GitHub Desktop.

Select an option

Save nauman/8557ce551d6910361c8f889a10c82fee to your computer and use it in GitHub Desktop.
AI Code Generation for Ruby on Rails
{
"meta": {
"context": "You are an expert programming AI assistant prioritizing minimalist, efficient code and accepting user preferences even if suboptimal.",
"interaction_rules": [
"Clearly display the current step of the plan being executed.",
"Ask for clarification if requirements are ambiguous.",
"Always optimize for minimal code complexity and resource overhead.",
"Explain reasoning at each step, highlighting assumptions and potential limitations."
],
"workflow": {
"role": "Expert software engineer focused on clean code, system design, and production-quality implementation.",
"steps": [
{
"title": "1. Requirements Analysis",
"details": [
"Break down functional requirements.",
"Define expected inputs/outputs.",
"Identify constraints and edge cases."
]
},
{
"title": "2. Technical Design",
"details": [
"Outline the system architecture or approach.",
"Select appropriate data structures and algorithms.",
"Identify necessary dependencies.",
"Consider performance and scalability."
]
},
{
"title": "3. Implementation & Review",
"details": [
"Develop modular, well-documented, and maintainable code.",
"Implement comprehensive error handling and logging.",
"Adhere to software engineering best practices (SOLID, DRY, KISS, Security).",
"Include unit tests where applicable.",
"Generate documentation following the specified guidelines.",
]
}
]
},
"documentation_guidelines": {
"style_preference": "Use Markdown format, following YARD-like conventions suitable for Ruby code.",
"required_elements": [
"Purpose: Clear, concise explanation of what the code (class, module, method) does.",
"Parameters (@param): For methods/functions, list each parameter with its expected type(s) and a clear description.",
"Return Value (@return): Describe the return value and its type(s). Specify if nothing is returned or if exceptions might be raised.",
"Usage Example: Provide one or more simple, practical code snippets demonstrating how to use the code.",
"Assumptions/Limitations: Note any important prerequisites, assumptions made, or known limitations/edge cases."
],
"placement": "Generate documentation as comments directly within the code (e.g., preceding methods/classes) or as a separate Markdown block when documenting a larger module, feature, or providing an overview."
}
},
"guidelines": {
"title": "Unified Software Engineering Guidelines",
"sections": [
{
"id": 1,
"title": "Vision and Philosophy",
"items": [
"Minimalism & Efficiency: Write clear, self-documenting code that is both minimal and effective—even if user preferences are suboptimal.",
"Iterative Development: Adopt a candidate mindset, iterating on tasks 3–5 times until they are robust.",
"Functionality First: Focus on delivering working solutions before engaging in premature optimization.",
"Avoid Premature Refactoring: Shift your focus away from early code polishing or refactoring."
]
},
{
"id": 2,
"title": "Core Engineering Principles",
"items": [
"SOLID Principles: Always follow SOLID principles.",
"DRY & KISS: Avoid repetition and unnecessary complexity.",
"Defensive Programming: Include input validation, error handling, and logging.",
"Security: Sanitize inputs and implement the principle of least privilege.",
"Performance & Scalability: Optimize code with consideration for time and space complexities."
]
},
{
"id": 3,
"title": "Class Design and Organization",
"items": [
"Meaningful Naming: Define a class with a meaningful name.",
"Service Naming: Avoid appending \"service\" if the class is located in the service folder.",
"Constants: Establish constants for any magic strings and numbers.",
"Favor Self-Contained Classes: Favor self-contained classes when an object isn't needed.",
"Nested Classes: Nest classes within classes if there are 3 to 5 repetitions.",
"Class Length: Aim to keep a class under 120 lines."
]
},
{
"id": 4,
"title": "Method Design and Implementation",
"items": [
"Conciseness: Keep method implementations concise, ideally not exceeding 5 to 8 lines.",
"Argument Limits: Limit the argument list to a maximum of 0 to 5.",
"Named Parameters: If argument names are tricky to recall, make them non-optional (e.g., (x: 34, y: 36) as named parameters).",
"Descriptive Naming: Method names can be longer but should be clear and descriptive, indicating their purpose."
]
},
{
"id": 5,
"title": "Dependency Management and State Handling",
"items": [
"Dependency Injection: Use dependency injections without coupling them.",
"State Management: Don't change object state within a service if the service is not about that data model."
]
},
{
"id": 6,
"title": "Service Patterns and Front-End Practices",
"items": [
"Service Objects: Create classes that adhere to the single responsibility principle.",
"Ruby on Rails Conventions: Follow Rails best practices for organizing classes and services.",
"Front-End Frameworks: Use Stimulus and Hotwire for front-end development."
]
},
{
"id": 7,
"title": "Testing, Logging, and Deployment",
"items": [
"Unit Testing: Write comprehensive tests that cover edge cases and potential errors.",
"Logging: Implement logging at appropriate levels to aid debugging and production monitoring.",
"CI/CD: Integrate continuous integration and deployment practices to maintain code quality and rapid iteration."
]
},
{
"id": 8,
"title": "Documentation and Iterative Improvement",
"items": [
"API Documentation: Provide clear documentation that explains the 'why' behind design decisions.",
"Iterative Enhancement: Continuously revisit and refine code until it meets our high standards for quality and clarity."
]
},
{
"id": 9,
"title": "References",
"items": [
"Official Ruby on Rails Guides: https://guides.rubyonrails.org/",
"Hotwire Documentation: https://hotwired.dev/",
"Phlex Documentation: https://www.phlex.fun/",
"Community Ruby Style Guide: https://github.com/rubocop/ruby-style-guide",
"Ruby on Rails Community Forum: https://rubyonrails.link/",
"Ruby on Rails Community Wiki: https://rubyonrails.link/wiki",
"Ruby on Rails Style guide: https://rails.rubystyle.guide",
"Ruby Style Guide: https://rubystyle.guide"
]
}
]
}
}
"gem_preferences": {
"styling": "Tailwind CSS",
"minimalist_components": "https://github.com/lazaronixon/css-zero",
"enhanced_ui_components": "https://github.com/phlex-ruby/phlex-rails"
},
"gems": {
"main_gems": [
{
"category": "Admin Panel",
"gems": [
{
"name": "rails-admin",
"description": "A framework for creating admin panels for Rails applications.",
"link": "https://github.com/railsadminteam/rails_admin"
}
]
},
{
"category": "Analytics",
"gems": [
{
"name": "ahoy_matey",
"description": "A library for tracking visits, events, and user behavior in Rails apps.",
"link": "https://github.com/ankane/ahoy"
}
]
},
{
"category": "Authorization",
"gems": [
{
"name": "cancancan",
"description": "Authorization library for controlling user access.",
"link": "https://github.com/CanCanCommunity/cancancan"
}
]
},
{
"category": "Code Documentation",
"gems": [
{
"name": "annotate",
"description": "Annotates Rails models, fixtures, and tests with schema information.",
"link": "https://github.com/ctran/annotate_models"
}
]
},
{
"category": "Code Quality",
"gems": [
{
"name": "rubocop",
"description": "A Ruby code style and linting tool.",
"link": "https://github.com/rubocop/rubocop"
},
{
"name": "rubocop-rails-omakase",
"description": "Rails-specific code linting standards for Rubocop.",
"link": "https://github.com/rubocop/rubocop-rails"
},
{
"name": "rubycritic",
"description": "A static code analysis tool that generates quality reports for Ruby projects.",
"link": "https://github.com/whitesmith/rubycritic"
}
]
},
{
"category": "Data Visualization",
"gems": [
{
"name": "chartkick",
"description": "Simplifies creating JavaScript charts in Rails apps.",
"link": "https://github.com/ankane/chartkick"
}
]
},
{
"category": "Feature Flags",
"gems": [
{
"name": "flipper",
"description": "A feature flagging library for enabling/disabling features.",
"link": "https://github.com/jnunemaker/flipper"
},
{
"name": "flipper-ui",
"description": "Provides a web interface for managing Flipper feature flags.",
"link": "https://github.com/jnunemaker/flipper"
}
]
},
{
"category": "Pagination",
"gems": [
{
"name": "pagy",
"description": "Ultra-lightweight pagination for Rails.",
"link": "https://github.com/ddnexus/pagy"
}
]
},
{
"category": "Payments",
"gems": [
{
"name": "pay",
"description": "Simplifies payment processing for Rails apps.",
"link": "https://github.com/pay-rails/pay"
},
{
"name": "stripe",
"description": "Library for integrating Stripe payment processing.",
"link": "https://github.com/stripe/stripe-ruby"
}
]
},
{
"category": "SEO",
"gems": [
{
"name": "sitemap-generator",
"description": "Generates sitemaps for Rails applications.",
"link": "https://github.com/kjvarga/sitemap_generator"
},
{
"name": "meta-tags",
"description": "Simplifies adding meta tags for SEO in Rails applications.",
"link": "https://github.com/kpumuk/meta-tags"
}
]
},
{
"category": "Design",
"gems": [
{
"name": "rails_icon",
"description": "Add any icon library to a Rails app. Rails Icons has first-party support for a handful of libraries. It is library agnostic so it can be used with any icon library using the same interface.",
"link": "https://github.com/Rails-Designer/rails_icons"
}
]
}
],
"nice_to_have": [
{
"category": "Audit Logging",
"gems": [
{
"name": "paper_trail",
"description": "Tracks changes to models over time.",
"link": "https://github.com/paper-trail-gem/paper_trail"
}
]
},
{
"category": "Scheduling",
"gems": [
{
"name": "whenever",
"description": "Cron job scheduler for Ruby applications.",
"link": "https://github.com/javan/whenever"
}
]
}
]
},

Rails 8 Standards & Best Practices Guide 2025

A comprehensive reference for modern Rails code standards, architectural patterns, and curated gem selection.


Part 1: Core Rails 8 Philosophy & Standards

Guiding Principles

Rails 8 is built on two foundational principles[44][51]:

  1. Convention Over Configuration (CoC) — Sensible defaults reduce decision fatigue, setup time, and encourage consistency
  2. Don't Repeat Yourself (DRY) — Code reuse through helpers, partials, scopes, and modules improves maintainability

Rails 8 Architecture: MVC + Layers

Model-View-Controller (MVC)[51]:

  • Model: Business logic, database interaction, validations, associations
  • View: Presentation layer, rendered to user interface
  • Controller: Request orchestration, data processing, response routing

Extended Modern Architecture[48]:

Client Layer        → React, Vue, Hotwire
API Layer           → Rails Controllers (input validation, routing)
Service Layer       → Business logic (Plain Ruby Objects)
Repository Layer    → Data access, query composition
Database Layer      → PostgreSQL, Redis persistence

New Rails 8 Features (Solid Stack)

Solid Suite[43][46] — Database-backed, Redis-free alternatives:

  • Solid Cache — Database-powered caching without Redis dependency
  • Solid Queue — Background jobs using database tables
  • Solid Cable — WebSocket management for real-time features

Modern Asset Pipeline[43][46]:

  • Propshaft replaces Sprockets for leaner asset management
  • Importmap-rails — Dependency pinning without npm/yarn
  • Turbo & Stimulus — Built-in frontend framework

Built-in Security & Quality[46]:

  • Brakeman (security scanner) included
  • RuboCop with omakase configuration built-in
  • GitHub Actions CI/CD workflow template
  • CSP (Content Security Policy) enforcement

Part 2: Code Standards & Best Practices

1. Naming Conventions

Meaningful Naming[52]:

  • Classes: Use descriptive, action-oriented names
  • Service objects: Verb + substantive (e.g., CreateUser, not UserCreation)
  • Scopes: Past tense action (e.g., published, expired)
  • Abbreviations: Avoid unless universally understood (e.g., Admin, not Adm)

Examples:

# Good
class User::Authenticate
class CreateSubscriptionService
class OrdersQuery

# Bad
class UserAction
class SubscriptionCreationService
class GetOrders

2. Method Length & Cyclomatic Complexity

Standards[52]:

  • Method length: Limit to 5–8 lines with 0–5 parameters
  • Class length: Keep under 120 lines
  • Nesting depth: Avoid deep "arrow code" (nested if statements)
  • Use guard clauses to flatten logic flow

Example:

# Bad — too long, nested
def process_payment(user, amount, card)
  if user.present?
    if user.active?
      if card.valid?
        charge = Card.charge(card, amount)
        if charge.success?
          user.update(balance: user.balance - amount)
          return { status: :success }
        end
      end
    end
  end
  { status: :failed }
end

# Good — guard clauses, extracted logic
def process_payment(user, amount, card)
  return { status: :invalid_user } unless user&.active?
  return { status: :invalid_card } unless card.valid?

  charge = Card.charge(card, amount)
  return { status: :charge_failed } unless charge.success?

  user.update(balance: user.balance - amount)
  { status: :success }
end

3. Model Design: Single Responsibility Principle

Best Practices[45][52]:

  • Avoid fat models — Keep only domain logic
  • No model callbacks — Use service objects instead
  • Prefer scopes over methods for queries
  • Use validations for data integrity
  • Delegate to concerns for cross-cutting logic
  • Prefer dependency injection over tight coupling

Anti-patterns to Avoid[54]:

  • Don't extract decorators/view models prematurely
  • Don't extract domain models until clearly needed
  • Don't use interactors from day one
  • Don't reach for advanced patterns too early

Example:

# Bad — bloated model
class User < ApplicationRecord
  after_create :send_welcome_email, :create_onboarding_tasks
  after_update :sync_to_crm, :update_analytics

  def send_welcome_email
    # complex email logic here
  end
end

# Good — clean model with service objects
class User < ApplicationRecord
  validates :email, presence: true, uniqueness: true
  has_many :posts

  scope :active, -> { where(archived_at: nil) }
end

class Users::SendWelcomeEmail
  def initialize(user)
    @user = user
  end

  def call
    UserMailer.with(user: @user).welcome_email.deliver_later
  end
end

4. Service Objects & Command Pattern[63][66][69]

When to use:

  • Multi-step processes (e.g., user signup, payment processing)
  • Business logic requiring external API calls
  • Replacing fat controllers or model callbacks
  • Encapsulating conditional logic ("Rule" objects)

Structure:

# app/services/orders/create.rb
module Orders
  class Create < ApplicationService
    attr_reader :user, :items

    def initialize(user, items)
      @user = user
      @items = items
    end

    # Single public method
    def call
      validate_items
      calculate_total
      create_order
    end

    private

    def validate_items
      raise StandardError, "No items" if items.empty?
    end

    def calculate_total
      @total = items.sum { |item| item.price * item.quantity }
    end

    def create_order
      Order.create(user: @user, total: @total, items: @items)
    end
  end
end

# Usage
result = Orders::Create.call(user, items)

Naming Convention: VerbSubstantive or VerbSubstantiveQuery

  • CreateOrder, CancelSubscription, FetchProductsQuery

5. Query Objects[63]

Purpose: Complex querying on ActiveRecord relations Structure:

class ProductsQuery
  attr_reader :relation

  def initialize(relation = Product.all)
    @relation = relation
  end

  def active
    relation.where(archived_at: nil)
  end

  def by_category(category)
    relation.joins(:category).where(categories: { id: category })
  end

  def recent
    relation.order(created_at: :desc)
  end

  def call
    active.by_category(@category).recent
  end
end

# Usage
ProductsQuery.new.active.by_category(electronics).recent

6. Form Objects[63]

Purpose: Replace strong parameters, handle virtual/composite resources, use callbacks safely Structure:

class UserRegistrationForm
  include ActiveModel::Model
  attr_accessor :name, :email, :password

  validates :email, presence: true, uniqueness: true
  validates :password, presence: true, length: { minimum: 8 }

  def save
    return false unless valid?
    User.create(name:, email:, password:)
  end
end

# Controller
def create
  form = UserRegistrationForm.new(user_params)
  if form.save
    redirect_to root_path
  else
    render :new
  end
end

7. Authorization: Pundit Pattern[53]

Best Practice: Keep authorization logic clean and centralized

class PostPolicy
  attr_reader :user, :post

  def initialize(user, post)
    @user = user
    @post = post
  end

  def update?
    user.admin? || user == post.author
  end

  def delete?
    user.admin?
  end
end

# Controller
def update
  @post = Post.find(params[:id])
  authorize(@post)
  @post.update(post_params)
end

8. RESTful Design[51]

Best Practice: Map HTTP verbs to CRUD operations

# Routes
resources :posts do
  member do
    get :archive       # GET /posts/:id/archive
    patch :unarchive   # PATCH /posts/:id/unarchive
  end

  collection do
    get :published     # GET /posts/published
  end
end

# Avoid
get 'posts/:id/archive_post'
patch 'posts/:id/unarchive_post'

9. Query Optimization[62]

Bullet gem — Detect N+1 queries and unused eager loading[59]

# Add to Gemfile (development group)
gem 'bullet', group: 'development'

# Configuration
Bullet.enable = true
Bullet.alert = true
Bullet.bullet_logger = true

# Example detection
# Instead of:
@posts = Post.all
@posts.each { |post| puts post.author.name }  # N+1 query

# Use:
@posts = Post.includes(:author)  # Eager load

10. Code Style: RuboCop Omakase

Rails 7.2+: RuboCop comes built-in with omakase defaults[55][58]

Key Omakase Rules[61]:

  • Line length: 120 characters max
  • Method length: Reasonable limits
  • Class length: Reasonable limits
  • Automatic formatting with bin/rubocop -a

Configuration:

# .rubocop.yml
inherit_gem:
  rubocop-rails-omakase: rubocop.yml

# Team customizations
Metrics/LineLength:
  Max: 120

AllCops:
  Exclude:
    - 'db/migrate/*'
    - 'vendor/**/*'

Part 3: Recommended Gems & Stack (2025)

Core Authentication & Authorization

Gem Purpose Why Use Notes
devise[53] User authentication Industry standard, feature-rich Handles registration, password reset, multi-factor auth
pundit[53] Authorization Clean policy classes in plain Ruby No DSL learning curve

Database & Querying

Gem Purpose Why Use Notes
pagy[53] Pagination Fast, minimal overhead Use instead of kaminari in 2025
bullet[62] N+1 query detection Catches performance issues during dev Development group only
annotate Model documentation Auto-generates schema comments Helps onboarding

Background Jobs & Scheduling

Gem Purpose Why Use Notes
sidekiq[53][56] Background jobs High-performance, multi-threaded Requires Redis; de facto standard
solid_queue Background jobs (Rails 8) Database-backed alternative No Redis dependency; batteries included
clockwork[54] Job scheduling Lightweight, simple to configure Alternative: sidekiq-cron (enterprise only)

File Uploads & Storage

Gem Purpose Why Use Notes
shrine[56] File uploads Modular, flexible, best-in-class Community favorite 2025; plugins for S3, R2, B2
aws-sdk-s3 AWS S3 integration Production storage backend Works with Shrine

Frontend & Interactivity

Gem Purpose Why Use Notes
turbo-rails[59] SPA-like updates Built-in; reduces JS needed Use Turbo Streams for real-time
stimulus-rails JS controller framework Built-in; minimal JavaScript Use with Turbo for interactivity
tailwindcss-rails[43] CSS framework Modern utility-first approach Rails 8 default
phlex-rails Component library Type-safe, performant components Modern replacement for ERB + Haml

Testing

Gem Purpose Why Use Notes
minitest Testing framework Rails default; lightweight Use unless team prefers RSpec
rspec-rails[53] BDD-style testing Popular alternative; readable syntax Higher learning curve than minitest
factory_bot[53] Test data generation Cleaner than fixtures; flexible Use with RSpec or minitest
shoulda-matchers[56] One-line test helpers Reduces boilerplate Test validations, associations with one line
simplecov[56] Code coverage Monitor test coverage % Integrate into CI/CD
timecop[56] Time-dependent testing Freeze/travel time in tests Essential for subscription/expiry testing

Code Quality & Security

Gem Purpose Why Use Notes
rubocop-rails-omakase[61] Code style linting Built-in with Rails 7.2+; zero-config Use omakase style; customize minimally
brakeman[46] Security scanning Built-in Rails 8; detects vulnerabilities Run in CI/CD; catches SQL injection, XSS
pry[53] Interactive debugging Better than binding.irb; explore variables Development group only

Caching

Gem Purpose Why Use Notes
solid_cache[60] Database caching Rails 8 built-in; no Redis Russian Doll (fragment) caching recommended

API Development

Gem Purpose Why Use Notes
active_model_serializers JSON serialization Consistent response formatting Pair with versioning (Versionist)
pundit Authorization in APIs Enforces permission checks Works seamlessly with API controllers

Admin Panels

Gem Purpose Why Use Notes
active_admin[59] Admin dashboards Instant admin UI; fully customizable Saves weeks of development

Monitoring & Observability

Gem Purpose Why Use Notes
datadog (paid) Monitoring, logging, APM Complete observability stack Production-grade monitoring
influxdb-rails (self-hosted) Metrics collection Alternative to Datadog; InfluxDB + Grafana Cost-effective for startups

Minimal Recommended Gemset (Fresh Rails 8 App)

# Gemfile

group :development, :test do
  gem 'pry-rails'
  gem 'factory_bot_rails'
end

group :development do
  gem 'rubocop-rails-omakase', require: false
  gem 'brakeman', require: false
  gem 'bullet'
  gem 'annotate'
end

# Production
gem 'devise'
gem 'pundit'
gem 'pagy'
gem 'shrine'
gem 'aws-sdk-s3' # If using S3 with Shrine
gem 'sidekiq'    # If async jobs needed
gem 'tailwindcss-rails'
gem 'phlex-rails'

Part 4: Architecture Patterns

Layered Application Structure

Standard Rails 8 Application Layers[48]:

app/
├── models/
│   ├── user.rb
│   ├── post.rb
│   └── concerns/
│       └── timestamps.rb
│
├── controllers/
│   ├── api/
│   │   └── posts_controller.rb
│   └── admin/
│       └── users_controller.rb
│
├── services/
│   └── orders/
│       ├── create.rb
│       ├── cancel.rb
│       └── application_service.rb
│
├── queries/
│   ├── products_query.rb
│   └── user_statistics_query.rb
│
├── policies/
│   ├── post_policy.rb
│   └── admin_policy.rb
│
├── forms/
│   └── user_registration_form.rb
│
├── views/
│   ├── posts/
│   │   ├── index.html.erb
│   │   └── show.html.erb
│   └── shared/
│       └── header.html.erb
│
├── mailers/
│   └── user_mailer.rb
│
├── jobs/
│   ├── send_welcome_email_job.rb
│   └── process_payment_job.rb
│
├── javascript/
│   ├── controllers/
│   │   └── posts_controller.js (Stimulus)
│   └── application.js
│
└── components/
    └── card_component.rb (Phlex)

RESTful Controller Design

Rails 8 Controller Best Practice:

module Api
  module V1
    class PostsController < ApplicationController
      def index
        authorize(Post)
        @posts = PostsQuery.new.published.recent
        render json: @posts
      end

      def show
        @post = Post.find(params[:id])
        authorize(@post)
        render json: @post
      end

      def create
        @post = CreatePost.call(current_user, post_params)
        render json: @post, status: :created
      rescue StandardError => e
        render json: { error: e.message }, status: :unprocessable_entity
      end
    end
  end
end

Database Design: Migrations & Constraints

Rails 8 Shorthand[46]:

# Shorthand for NOT NULL constraints
rails g resource Product title:string! description:text brand:references

# Generated migration with ! shorthand automatically applies NOT NULL
class CreateProducts < ActiveRecord::Migration[8.0]
  def change
    create_table :products do |t|
      t.string :title, null: false
      t.text :description
      t.references :brand

      t.timestamps
    end
  end
end

Part 5: Testing Standards

Test Structure

Minitest (Rails default):

# test/models/user_test.rb
require "test_helper"

class UserTest < ActiveSupport::TestCase
  test "user is valid with email" do
    user = User.new(email: "test@example.com")
    assert user.valid?
  end

  test "user requires email" do
    user = User.new
    assert_not user.valid?
  end
end

# test/services/orders/create_test.rb
require "test_helper"

class Orders::CreateTest < ActiveSupport::TestCase
  test "creates order with valid items" do
    user = users(:one)
    items = [products(:one)]
    
    result = Orders::Create.call(user, items)
    
    assert result.persisted?
    assert_equal 1, result.items.count
  end
end

Test Coverage Goals[56]:

  • Minimum 80% code coverage
  • Unit tests for all services
  • System tests for critical user flows
  • Integration tests for API endpoints

Part 6: Deployment & DevOps

Docker & Kamal (Rails 8 Default)

Rails 8 includes Docker support[46]:

  • Dockerfile automatically generated
  • kamal init for deployment configuration
  • Support for multi-container orchestration
  • GitHub Actions CI/CD workflow template included

Production Checklist

  • ✅ Brakeman security scan in CI/CD
  • ✅ RuboCop linting enforced
  • ✅ Test coverage minimum 80%
  • ✅ All migrations reversible
  • ✅ Secrets managed via environment variables
  • ✅ CSP headers configured
  • ✅ Error tracking (Sentry, Rollbar, or Datadog)
  • ✅ Logging centralized (if scaling beyond single instance)
  • ✅ Database backups automated

Conclusion

Rails 8 in 2025 emphasizes:

  • Simplicity: Solid Stack eliminates Redis/external dependencies
  • Security: Built-in scanning and strong defaults
  • Developer Experience: Omakase defaults, zero-config setup
  • Performance: Propshaft, importmap, optimized queries
  • Modularity: Clean separation of concerns with service objects

Follow these standards, use the recommended gems judiciously, and your Rails 8 applications will be maintainable, performant, and scalable.


Key References

  • Rails 8 Upgrade Guide & New Features[43][46]
  • Convention Over Configuration Philosophy[44][51]
  • Service Objects & Design Patterns[63][65][66][69]
  • Essential Gems for 2025[53][56][59]
  • Code Standards & Best Practices[52][58][61][62]
  • Architecture Patterns[48][64][70]
  • Testing Strategies[56]
{
"project_name": "Modern Rails Application",
"document_purpose": "This document defines essential project requirements, tracks development progress, and provides implementation guidelines for a Ruby on Rails application with Hotwire and Phlex.",
"tech_stack": {
"backend": "Ruby on Rails 8+",
"frontend": "Hotwire (Turbo + Stimulus)",
"view_components": "Phlex with RubyUI.com components",
"styling": "Tailwind CSS",
"database": "PostgreSQL",
"testing": "mini tests"
},
"principles": [
"Each requirement must include clear setup steps, implementation details, and test commands",
"Follow Ruby on Rails conventions and modern best practices",
"Use Hotwire for dynamic interfaces without heavy JavaScript",
"Leverage Phlex for type-safe view components with Ruby syntax",
"Prioritize maintainability, testability, and developer experience"
],
"requirements_format": {
"functional_requirement": {
"id": "Unique identifier (REQ-FUNC-XXX)",
"name": "Short descriptive name",
"description": "Detailed explanation of the requirement",
"status": ["pending", "in_progress", "completed", "blocked"],
"priority": ["high", "medium", "low"],
"files_affected": {
"new": ["List of files to be created"],
"modified": ["List of files to be modified"],
"deleted": ["List of files to be deleted"]
},
"database_changes": {
"tables": ["Tables that need to be created or modified"],
"migrations": ["Migration names required"]
},
"implementation_details": {
"gems": ["Required gems with versions"],
"setup_steps": ["Step-by-step implementation instructions"],
"code_examples": ["Key code snippets showing implementation approach"]
},
"testing_strategy": {
"unit_tests": ["Description of unit tests to be created"],
"integration_tests": ["Description of integration tests to be created"],
"test_commands": ["Commands to run for testing this requirement"]
},
"hotwire_components": {
"turbo_frames": ["Description of Turbo Frames to implement"],
"turbo_streams": ["Description of Turbo Streams to implement"],
"stimulus_controllers": ["Description of Stimulus controllers to implement"]
},
"phlex_components": {
"component_structure": "Description of Phlex component hierarchy",
"reusable_components": ["List of reusable Phlex components to create"]
}
},
"non_functional_requirement": {
"id": "Unique identifier (REQ-NFR-XXX)",
"name": "Short descriptive name",
"description": "Detailed explanation of the requirement",
"status": ["pending", "in_progress", "completed", "blocked"],
"priority": ["high", "medium", "low"],
"category": ["performance", "security", "scalability", "accessibility", "usability"],
"acceptance_criteria": ["Measurable criteria for requirement fulfillment"],
"implementation_approach": ["How this requirement will be addressed"],
"testing_strategy": {
"benchmark_tests": ["Performance tests to be conducted"],
"load_tests": ["Load testing approach"],
"security_tests": ["Security testing approach"],
"test_commands": ["Commands to verify this requirement"]
}
}
},
"progress_tracking": {
"feature_implementation_log": {
"entry_format": {
"date": "YYYY-MM-DD",
"feature": "Feature name",
"developer": "Developer name",
"requirements_addressed": ["REQ-FUNC-XXX", "REQ-NFR-XXX"],
"changes_implemented": {
"description": "Summary of changes made",
"files_changed": ["List of files changed"],
"commits": ["Relevant commit hashes"]
},
"challenges": ["Description of any challenges encountered"],
"solutions": ["How challenges were resolved"],
"next_steps": ["Planned next implementation steps"]
}
},
"error_tracking": {
"entry_format": {
"error_id": "ERR-XXX",
"description": "Brief description of the error",
"status": ["open", "investigating", "resolved"],
"environment": ["development", "test", "production"],
"related_requirements": ["REQ-FUNC-XXX"],
"error_details": {
"location": "File path and line number",
"stack_trace": "Relevant portion of stack trace",
"error_message": "Exact error message"
},
"diagnosis": "Analysis of the root cause",
"resolution": {
"fix_description": "Description of the fix implemented",
"files_changed": ["List of files modified to fix the issue"],
"commits": ["Commit hash with the fix"]
}
}
}
},
"sample_requirements": [
{
"id": "REQ-FUNC-001",
"name": "User Authentication with Devise",
"description": "Implement secure user authentication with Devise, including sign-up, login, and password reset functionality",
"status": "pending",
"priority": "high",
"files_affected": {
"new": [
"app/models/user.rb",
"app/views/devise/*",
"app/components/users/authentication_form.rb"
],
"modified": [
"config/routes.rb",
"app/controllers/application_controller.rb"
],
"deleted": []
},
"database_changes": {
"tables": ["users"],
"migrations": ["DeviseCreateUsers"]
},
"implementation_details": {
"gems": ["devise ~> 4.9"],
"setup_steps": [
"Add 'devise' gem to Gemfile",
"Run bundle install",
"Run rails generate devise:install",
"Configure Devise in config/initializers/devise.rb",
"Generate User model: rails generate devise User",
"Run rails db:migrate",
"Create Phlex component for authentication forms"
],
"code_examples": [
"# app/components/users/authentication_form.rb\nmodule Users\n class AuthenticationForm < ApplicationComponent\n def initialize(resource:, url:, method: :post)\n @resource = resource\n @url = url\n @method = method\n end\n\n def template\n RubyUI::Form.new(action: @url, method: @method) do\n div(class: \"space-y-4\") do\n div do\n RubyUI::Label.new(for: \"email\") { \"Email\" }\n RubyUI::Input.new(type: \"email\", name: \"email\", id: \"email\", required: true)\n end\n \n div do\n RubyUI::Label.new(for: \"password\") { \"Password\" }\n RubyUI::Input.new(type: \"password\", name: \"password\", id: \"password\", required: true)\n end\n \n div do\n RubyUI::Button.new(type: \"submit\", variant: \"primary\") { \"Sign in\" }\n end\n end\n end\n end\n end\nend"
]
},
"testing_strategy": {
"unit_tests": [
"Test User model validations and associations",
"Test authentication success and failure cases"
],
"integration_tests": [
"Test user registration flow",
"Test login and logout process",
"Test password reset functionality"
],
"test_commands": [
"rspec spec/models/user_spec.rb",
"rspec spec/system/user_authentication_spec.rb"
]
},
"hotwire_components": {
"turbo_frames": [
"Login form in turbo frame for modal display"
],
"turbo_streams": [
"Update header with user info on successful authentication"
],
"stimulus_controllers": [
"Authentication controller for form validation and submission"
]
},
"phlex_components": {
"component_structure": "Utilize Ruby UI components from rubyui.com with Phlex for authentication forms",
"reusable_components": [
"RubyUI::Form",
"RubyUI::Input",
"RubyUI::Button",
"RubyUI::Alert"
]
}
},
{
"id": "REQ-FUNC-002",
"name": "Reactive UI with Hotwire and Phlex",
"description": "Implement a modern, reactive UI using Hotwire (Turbo + Stimulus) with Phlex components for server-rendered views",
"status": "pending",
"priority": "high",
"files_affected": {
"new": [
"app/components/application_component.rb",
"app/components/ui/button.rb",
"app/components/ui/card.rb",
"app/components/ui/form.rb",
"app/javascript/controllers/live_update_controller.js"
],
"modified": [
"app/views/layouts/application.html.erb",
"config/importmap.rb"
],
"deleted": []
},
"database_changes": {
"tables": [],
"migrations": []
},
"implementation_details": {
"gems": [
"phlex-rails ~> 1.0",
"turbo-rails ~> 1.4",
"stimulus-rails ~> 1.2",
"ruby_ui ~> 0.1"
],
"setup_steps": [
"Add required gems to Gemfile",
"Run bundle install",
"Set up base ApplicationComponent for Phlex",
"Create reusable UI components using Phlex",
"Configure Stimulus controllers for interactive behavior",
"Implement Turbo Frames and Streams for real-time updates"
],
"code_examples": [
"# app/components/dashboard/stats_card.rb\nmodule Dashboard\n class StatsCard < ApplicationComponent\n def initialize(title:, value:, change: nil, change_type: nil)\n @title = title\n @value = value\n @change = change\n @change_type = change_type # :increase or :decrease\n end\n\n def template\n RubyUI::Card.new do\n div(class: \"p-4\") do\n h3(class: \"text-sm font-medium text-gray-500\") { @title }\n div(class: \"mt-1 flex items-baseline\") do\n p(class: \"text-2xl font-semibold text-gray-900\") { @value }\n if @change.present?\n p(class: change_class) do\n span(class: \"sr-only\") { @change_type == :increase ? \"Increased by\" : \"Decreased by\" }\n \" #{@change}%\"\n end\n end\n end\n end\n end\n end\n \n private\n \n def change_class\n base_class = \"ml-2 text-sm font-semibold\"\n if @change_type == :increase\n \"#{base_class} text-green-600\"\n else\n \"#{base_class} text-red-600\"\n end\n end\n end\nend"
]
},
"testing_strategy": {
"unit_tests": [
"Test Phlex component rendering",
"Test Stimulus controller behavior"
],
"integration_tests": [
"Test user interactions with Turbo and Stimulus",
"Test real-time updates with Turbo Streams"
],
"test_commands": [
"rspec spec/components/ui/button_spec.rb",
"rspec spec/system/interactive_ui_spec.rb"
]
},
"hotwire_components": {
"turbo_frames": [
"Content frames for partial page updates",
"Form frames for in-place editing"
],
"turbo_streams": [
"Real-time updates for data changes",
"Toast notifications for user feedback"
],
"stimulus_controllers": [
"live-update-controller for auto-refreshing content",
"form-controller for enhanced form interactions",
"modal-controller for modal dialogs"
]
},
"phlex_components": {
"component_structure": "Create a hierarchy of UI components with ApplicationComponent as the base class",
"reusable_components": [
"UI::Button",
"UI::Card",
"UI::Form",
"UI::Modal",
"UI::Notification"
]
}
},
{
"id": "REQ-NFR-001",
"name": "Performance Optimization",
"description": "Ensure the application loads and responds quickly under various conditions",
"status": "pending",
"priority": "medium",
"category": "performance",
"acceptance_criteria": [
"Page load time under 1.5 seconds for the main application pages",
"Server response time under 200ms for API endpoints",
"Smooth scrolling and interactions at 60fps"
],
"implementation_approach": [
"Set up proper caching with Redis",
"Configure Turbo Drive for faster navigation",
"Implement view component caching with Phlex",
"Use database query optimization techniques",
"Configure proper Puma settings for production"
],
"testing_strategy": {
"benchmark_tests": [
"Benchmark page load times with rack-mini-profiler",
"Measure database query performance"
],
"load_tests": [
"Use k6 or ApacheBench for simulating concurrent users",
"Test with realistic user scenarios"
],
"security_tests": [],
"test_commands": [
"RAILS_ENV=production bundle exec rake perf:test",
"k6 run load_test.js"
]
}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment