|
| 1 | +--- |
| 2 | +description: 'Ruby on Rails coding conventions and guidelines' |
| 3 | +applyTo: '**/*.rb' |
| 4 | +--- |
| 5 | + |
| 6 | +# Ruby on Rails |
| 7 | + |
| 8 | +## General Guidelines |
| 9 | + |
| 10 | +- Follow the RuboCop Style Guide and use tools like `rubocop`, `standardrb`, or `rufo` for consistent formatting. |
| 11 | +- Use snake_case for variables/methods and CamelCase for classes/modules. |
| 12 | +- Keep methods short and focused; use early returns, guard clauses, and private methods to reduce complexity. |
| 13 | +- Favor meaningful names over short or generic ones. |
| 14 | +- Comment only when necessary — avoid explaining the obvious. |
| 15 | +- Apply the Single Responsibility Principle to classes, methods, and modules. |
| 16 | +- Prefer composition over inheritance; extract reusable logic into modules or services. |
| 17 | +- Keep controllers thin — move business logic into models, services, or command/query objects. |
| 18 | +- Apply the “fat model, skinny controller” pattern thoughtfully and with clean abstractions. |
| 19 | +- Extract business logic into service objects for reusability and testability. |
| 20 | +- Use partials or view components to reduce duplication and simplify views. |
| 21 | +- Use `unless` for negative conditions, but avoid it with `else` for clarity. |
| 22 | +- Avoid deeply nested conditionals — favor guard clauses and method extractions. |
| 23 | +- Use safe navigation (`&.`) instead of multiple `nil` checks. |
| 24 | +- Prefer `.present?`, `.blank?`, and `.any?` over manual nil/empty checks. |
| 25 | +- Follow RESTful conventions in routing and controller actions. |
| 26 | +- Use Rails generators to scaffold resources consistently. |
| 27 | +- Use strong parameters to whitelist attributes securely. |
| 28 | +- Prefer enums and typed attributes for better model clarity and validations. |
| 29 | +- Keep migrations database-agnostic; avoid raw SQL when possible. |
| 30 | +- Always add indexes for foreign keys and frequently queried columns. |
| 31 | +- Define `null: false` and `unique: true` at the DB level, not just in models. |
| 32 | +- Use `find_each` for iterating over large datasets to reduce memory usage. |
| 33 | +- Scope queries in models or use query objects for clarity and reuse. |
| 34 | +- Use `before_action` callbacks sparingly — avoid business logic in them. |
| 35 | +- Use `Rails.cache` to store expensive computations or frequently accessed data. |
| 36 | +- Construct file paths with `Rails.root.join(...)` instead of hardcoding. |
| 37 | +- Use `class_name` and `foreign_key` in associations for explicit relationships. |
| 38 | +- Keep secrets and config out of the codebase using `Rails.application.credentials` or ENV variables. |
| 39 | +- Write isolated unit tests for models, services, and helpers. |
| 40 | +- Cover end-to-end logic with request/system tests. |
| 41 | +- Use background jobs (ActiveJob) for non-blocking operations like sending emails or calling APIs. |
| 42 | +- Use `FactoryBot` (RSpec) or fixtures (Minitest) to set up test data cleanly. |
| 43 | +- Avoid using `puts` — debug with `byebug`, `pry`, or logger utilities. |
| 44 | +- Document complex code paths and methods with YARD or RDoc. |
| 45 | + |
| 46 | +## App Directory Structure |
| 47 | + |
| 48 | +- Define service objects in the `app/services` directory to encapsulate business logic. |
| 49 | +- Use form objects located in `app/forms` to manage validation and submission logic. |
| 50 | +- Implement JSON serializers in the `app/serializers` directory to format API responses. |
| 51 | +- Define authorization policies in `app/policies` to control user access to resources. |
| 52 | +- Structure the GraphQL API by organizing schemas, queries, and mutations inside `app/graphql`. |
| 53 | +- Create custom validators in `app/validators` to enforce specialized validation logic. |
| 54 | +- Isolate and encapsulate complex ActiveRecord queries in `app/queries` for better reuse and testability. |
| 55 | +- Define custom data types and coercion logic in the `app/types` directory to extend or override ActiveModel type behavior. |
| 56 | + |
| 57 | +## Commands |
| 58 | + |
| 59 | +- Use `rails generate` to create new models, controllers, and migrations. |
| 60 | +- Use `rails db:migrate` to apply database migrations. |
| 61 | +- Use `rails db:seed` to populate the database with initial data. |
| 62 | +- Use `rails db:rollback` to revert the last migration. |
| 63 | +- Use `rails console` to interact with the Rails application in a REPL environment. |
| 64 | +- Use `rails server` to start the development server. |
| 65 | +- Use `rails test` to run the test suite. |
| 66 | +- Use `rails routes` to list all defined routes in the application. |
| 67 | +- Use `rails assets:precompile` to compile assets for production. |
| 68 | + |
| 69 | + |
| 70 | +## API Development Best Practices |
| 71 | + |
| 72 | +- Structure routes using Rails' `resources` to follow RESTful conventions. |
| 73 | +- Use namespaced routes (e.g., `/api/v1/`) for versioning and forward compatibility. |
| 74 | +- Serialize responses using `ActiveModel::Serializer` or `fast_jsonapi` for consistent output. |
| 75 | +- Return proper HTTP status codes for each response (e.g., 200 OK, 201 Created, 422 Unprocessable Entity). |
| 76 | +- Use `before_action` filters to load and authorize resources, not business logic. |
| 77 | +- Leverage pagination (e.g., `kaminari` or `pagy`) for endpoints returning large datasets. |
| 78 | +- Rate limit and throttle sensitive endpoints using middleware or gems like `rack-attack`. |
| 79 | +- Return errors in a structured JSON format including error codes, messages, and details. |
| 80 | +- Sanitize and whitelist input parameters using strong parameters. |
| 81 | +- Use custom serializers or presenters to decouple internal logic from response formatting. |
| 82 | +- Avoid N+1 queries by using `includes` when eager loading related data. |
| 83 | +- Implement background jobs for non-blocking tasks like sending emails or syncing with external APIs. |
| 84 | +- Log request/response metadata for debugging, observability, and auditing. |
| 85 | +- Document endpoints using OpenAPI (Swagger), `rswag`, or `apipie-rails`. |
| 86 | +- Use CORS headers (`rack-cors`) to allow cross-origin access to your API when needed. |
| 87 | +- Ensure sensitive data is never exposed in API responses or error messages. |
| 88 | + |
| 89 | +## Frontend Development Best Practices |
| 90 | + |
| 91 | +- Use `app/javascript` as the main directory for managing JavaScript packs, modules, and frontend logic in Rails 6+ with Webpacker or esbuild. |
| 92 | +- Structure your JavaScript by components or domains, not by file types, to keep things modular. |
| 93 | +- Leverage Hotwire (Turbo + Stimulus) for real-time updates and minimal JavaScript in Rails-native apps. |
| 94 | +- Use Stimulus controllers for binding behavior to HTML and managing UI logic declaratively. |
| 95 | +- Organize styles using SCSS modules, Tailwind, or BEM conventions under `app/assets/stylesheets`. |
| 96 | +- Keep view logic clean by extracting repetitive markup into partials or components. |
| 97 | +- Use semantic HTML tags and follow accessibility (a11y) best practices across all views. |
| 98 | +- Avoid inline JavaScript and styles; instead, move logic to separate `.js` or `.scss` files for clarity and reusability. |
| 99 | +- Optimize assets (images, fonts, icons) using the asset pipeline or bundlers for caching and compression. |
| 100 | +- Use `data-*` attributes to bridge frontend interactivity with Rails-generated HTML and Stimulus. |
| 101 | +- Test frontend functionality using system tests (Capybara) or integration tests with tools like Cypress or Playwright. |
| 102 | +- Use environment-specific asset loading to prevent unnecessary scripts or styles in production. |
| 103 | +- Follow a design system or component library to keep UI consistent and scalable. |
| 104 | +- Optimize time-to-first-paint (TTFP) and asset loading using lazy loading, Turbo Frames, and deferring JS. |
| 105 | + |
| 106 | +## Testing Guidelines |
| 107 | + |
| 108 | +- Write unit tests for models using `test/models` (Minitest) or `spec/models` (RSpec) to validate business logic. |
| 109 | +- Use fixtures (Minitest) or factories with `FactoryBot` (RSpec) to manage test data cleanly and consistently. |
| 110 | +- Organize controller specs under `test/controllers` or `spec/requests` to test RESTful API behavior. |
| 111 | +- Prefer `before` blocks in RSpec or `setup` in Minitest to initialize common test data. |
| 112 | +- Avoid hitting external APIs in tests — use `WebMock`, `VCR`, or `stub_request` to isolate test environments. |
| 113 | +- Use `system tests` in Minitest or `feature specs` with Capybara in RSpec to simulate full user flows. |
| 114 | +- Isolate slow and expensive tests (e.g., external services, file uploads) into separate test types or tags. |
| 115 | +- Run test coverage tools like `SimpleCov` to ensure adequate code coverage. |
| 116 | +- Avoid `sleep` in tests; use `perform_enqueued_jobs` (Minitest) or `ActiveJob::TestHelper` with RSpec. |
| 117 | +- Use database cleaning tools (`rails test:prepare`, `DatabaseCleaner`, or `transactional_fixtures`) to maintain clean state between tests. |
| 118 | +- Test background jobs by enqueuing and performing jobs using `ActiveJob::TestHelper` or `have_enqueued_job` matchers. |
| 119 | +- Ensure tests run consistently across environments using CI tools (e.g., GitHub Actions, CircleCI). |
| 120 | +- Use custom matchers (RSpec) or custom assertions (Minitest) for reusable and expressive test logic. |
| 121 | +- Tag tests by type (e.g., `:model`, `:request`, `:feature`) for faster and targeted test runs. |
| 122 | +- Avoid brittle tests — don’t rely on specific timestamps, randomized data, or order unless explicitly necessary. |
| 123 | +- Write integration tests for end-to-end flows across multiple layers (model, view, controller). |
| 124 | +- Keep tests fast, reliable, and as DRY as production code. |
0 commit comments