|
| 1 | +# [APP_NAME] |
| 2 | + |
| 3 | +[One sentence: what the app does and who it serves.] |
| 4 | + |
| 5 | +## Commands |
| 6 | + |
| 7 | +```bash |
| 8 | +bin/rails server # Start dev server |
| 9 | +bin/rails spec # Full test suite (Suspenders rake task) |
| 10 | +bundle exec rspec spec/models # Model specs only |
| 11 | +bundle exec rspec spec/requests # Request specs only |
| 12 | +bundle exec rspec spec/path/to/file_spec.rb # Run all tests in file |
| 13 | +bundle exec rspec spec/path/to/file_spec.rb:72 # Run just the test at line 72 |
| 14 | +rake standard # Lint |
| 15 | +rake standard:fix # Auto-fix lint issues |
| 16 | +bin/rails db:migrate # Run migrations |
| 17 | +bin/rails suspenders:db:migrate # Migrate + annotate |
| 18 | +bin/rails suspenders:cleanup:organize_gemfile # Sort Gemfile |
| 19 | +bundle audit # Check gem vulnerabilities |
| 20 | +bin/rails routes # View routes |
| 21 | +``` |
| 22 | + |
| 23 | +## Controllers |
| 24 | + |
| 25 | +- Controllers handle HTTP only: receive request, delegate to model, return response. |
| 26 | +- Actions should not exceed 10 lines (excluding strong params). Longer actions often signal business logic that belongs in a model or PORO. |
| 27 | +- Maximum one instance variable per action. |
| 28 | +- No business logic, calculations, email sending, or multi-object operations in controllers. |
| 29 | +- Always use strong parameters. Never `params.permit!`. |
| 30 | +- Return `status: :unprocessable_entity` on failed form renders (required by Turbo). |
| 31 | +- Prefer RESTful routes. Custom verb actions (e.g., post "activate") usually mean a missing noun/resource (e.g., resource :trial, only: [:create]). |
| 32 | + |
| 33 | +## Models & Domain Objects |
| 34 | + |
| 35 | +- No service objects. All domain classes live in `app/models/` with namespaces, never `app/services/`. |
| 36 | +- Name classes after domain nouns, not actions. No `*Service`, `*Manager`, `*Handler` suffixes. |
| 37 | +- Use `ActiveModel::Model` for POROs that need validation or form integration. |
| 38 | +- Replace `.call` / `.perform` with domain verbs: `#save`, `#complete`, `#submit`, `#deliver`. |
| 39 | +- Look to identify domain models that can be extracted when an existing |
| 40 | + model exceeds: 200 lines, 15 public methods, or 7 private methods. |
| 41 | +- Callbacks only for data integrity (normalise fields, set defaults). Never for emails, payments, or external systems. |
| 42 | +- Prefer composition over inheritance. Extract behaviour into small, focused objects. |
| 43 | +- Avoid feature envy, long parameter lists (max 3 args), case statements on type, and mixin abuse. |
| 44 | + |
| 45 | +## Testing |
| 46 | + |
| 47 | +- Must use TDD. Write tests first and follow red, green, refactor. |
| 48 | +- Must not use let or before in specs (avoid mystery guests). Do test setup |
| 49 | + within each test. |
| 50 | +- Test behaviour, not implementation. Four Phase Test: setup, exercise, verify, teardown. |
| 51 | +- Test pyramid: many model/PORO unit specs, some request specs, few system specs. |
| 52 | +- Every public method on every model and PORO must have at least one spec. |
| 53 | +- Every branch in a conditional must have at least one spec. |
| 54 | +- Use `build` / `build_stubbed` over `create` unless persistence is needed. |
| 55 | +- Factories: only required attributes with sensible defaults. Start in `spec/factories.rb`. |
| 56 | +- Shoulda Matchers for validations and associations. |
| 57 | +- WebMock blocks all external HTTP in tests — always stub external requests. |
| 58 | +- One `expect` per `it` block. Max 2 levels of context nesting. |
| 59 | +- Never test private methods directly. Never stub the system under test. |
| 60 | + |
| 61 | +## Security |
| 62 | + |
| 63 | +- Never interpolate user input into SQL. Use parameterised queries or `where(key: value)`. |
| 64 | +- Always use strong parameters. Never `params.permit!`. |
| 65 | +- Scope all queries to the current user or use Pundit authorisation. |
| 66 | +- Every controller must have authentication unless explicitly public. |
| 67 | +- Never use `raw`, `html_safe`, or `<%==` with user-supplied data. |
| 68 | +- Never skip CSRF verification for browser-facing controllers. |
| 69 | +- Filter sensitive params in logs: passwords, tokens, secrets, API keys. |
| 70 | +- Never `render json: model` without explicit `only:` — whitelist attributes. |
| 71 | +- Never redirect to `params[:return_to]` without validation. |
| 72 | +- Use array form for system commands: `system("cmd", arg)`, never `system("cmd #{arg}")`. |
| 73 | + |
| 74 | +## Views & Presenters |
| 75 | + |
| 76 | +- Views render data. No calculations, queries, or complex conditionals. |
| 77 | +- Use presenters to display logic. Instantiate in controller, use in view. |
| 78 | +- Extract repeated markup into partials. Pass data via `locals:`, not instance variables. |
| 79 | +- Helpers for simple formatting only (dates, currencies). If longer than 5 lines, use a presenter. |
| 80 | +- Turbo: return `status: :unprocessable_entity` on failed forms. Keep Stimulus controllers small. |
| 81 | + |
| 82 | +## Database & Migrations |
| 83 | + |
| 84 | +- Always use the `rails generate migration` command to create migration files. |
| 85 | +- Migrations must be reversible. |
| 86 | +- Add `null: false` and database-level defaults where appropriate. |
| 87 | +- Use `text` over `string` if length varies significantly. |
| 88 | +- Wrap multi-record operations in transactions. Use `save!` (bang) inside transactions. |
| 89 | +- Keep scopes as one-liners. Complex queries belong in search/query objects. |
| 90 | +- Never use `Post.all` without pagination. |
| 91 | +- Avoid `.count` in loops. |
| 92 | +- Use `counter_cache`. |
0 commit comments