Agent skill
rails-auto-assigned-field-validation
Fix for Rails models where validates :field, presence: true causes ALL creates to fail when the field is set by a before_create callback. Use when: (1) validates :number, presence: true is added to a model that uses before_create to auto-assign a sequence number, (2) model creates silently fail with "number can't be blank", (3) auto-generated fields (number, slug, token) fail presence validation despite being set in callbacks. Root cause: before_create runs AFTER validations. Fix: change before_create to before_validation on: :create.
Install this agent skill to your Project
npx add-skill https://github.com/yorch/claude-skills/tree/main/rails-auto-assigned-field-validation
SKILL.md
Rails Auto-Assigned Field Validation
Problem
Adding validates :number, presence: true to a model that auto-assigns number
in a before_create callback causes all creates to fail with a validation error
("number can't be blank"), even though the number is being set.
Context / Trigger Conditions
- Model has a
before_createthat assigns a field (e.g., sequence number, slug, token) - Adding a
presence: truevalidation on that field breaks all creates - Error: "FieldName can't be blank" on new records
- Existing records are fine; only creates fail
- Common with auto-incrementing record numbers:
self.number = (Model.maximum(:number) || 0) + 1
Root Cause
Rails callback execution order:
1. before_validation
2. **validates** ← runs HERE
3. before_save
4. before_create ← field is assigned HERE (too late!)
5. INSERT
6. after_create
7. after_save
When before_create assigns the field, validations have already run — the field is
still blank when validated.
Solution
Change before_create to before_validation on: :create:
# ❌ BROKEN — validation runs before the field is assigned
validates :number, :entry_date, presence: true
before_create :assign_number
# ✅ CORRECT — field is assigned before validation
validates :number, :entry_date, presence: true
before_validation :assign_number, on: :create
private
def assign_number
self.number = (self.class.maximum(:number) || 0) + 1
end
The on: :create guard ensures the callback only runs on create, not on every
valid? call (which could re-assign the number on updates).
Verification
# Should now pass
record = Model.new(required_attrs)
record.valid? # => true (number is now set before validation)
record.save # => true
record.number # => 1 (or next sequence)
Example (this codebase)
app/models/corrective_maintenance.rb and preventive_maintenance.rb both
auto-assign number with MAX(number) + 1. When validates :number, presence: true
was added, all creates broke until the callback was changed:
# app/models/corrective_maintenance.rb
validates :entry_date, :entry_km, :number, presence: true
before_validation :assign_number, on: :create # was: before_create
private
def assign_number
self.number = (CorrectiveMaintenance.maximum(:number) || 0) + 1
end
Notes
- This applies to any auto-generated field: slugs, tokens, UUIDs (when generated in Ruby), serial numbers, etc.
- The
on: :createis important — without it,assign_numberfires on everysave, which would reassign the number on updates and break uniqueness - ActiveRecord unique index (
UNIQUEconstraint) still provides DB-level protection; the presence validation is a Ruby-layer guard for cleaner error messages - Race condition mitigation: even with
before_validation, MAX()+1 is still raceable; pair withrescue ActiveRecord::RecordNotUniqueretry logic in mutations/controllers
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
typescript-unknown-jsx-expression
Fix TypeScript error "Type 'unknown' is not assignable to type ReactNode" when using Record<string, unknown> values directly in JSX && short-circuit expressions. Use when: (1) JSX expression {someObj.field && <Component />} fails with TS2322, (2) Reading from a JSON or untyped object via bracket notation in JSX conditionals, (3) Values typed as unknown appear in JSX even when wrapped in String() or guarded with truthiness checks. Fix: use !! to coerce to boolean before the && operator.
gha-docker-publish
ALWAYS invoke this skill before writing any GitHub Actions workflow that builds or pushes Docker images — it contains specific opinionated patterns that produce secure, reliable workflows and that you cannot reliably guess. The conventions it enforces include: (1) datetime+SHA image tags in YYYYMMDDHHMMSS_sha format for unambiguous build traceability, (2) a `workflow_dispatch` boolean `push` input that defaults to `false` (safe dry-run by default — a common mistake is using `type:choice` with `dry_run` inversion instead), (3) a `publish-docker` PR label gate that lets CI validate builds on PRs without pushing, (4) conditional `latest` tag using `enable={{is_default_branch}}` (never hardcoded `enable=true`), (5) GHA layer cache with `mode=max` for maximum rebuild speed, (6) no inline `${{ github.sha }}` in `run:` scripts (security hardening), (7) dual-registry login and push patterns when publishing to both GHCR and a private registry. Use this whenever the user asks to: set up GHCR publishing, add a docker-publish.yml workflow, add layer caching to Docker CI, configure datetime/SHA image tags, add a manual build-only dispatch trigger, push to multiple registries, or build Docker images on PRs.
prisma-7-docker-migrations
Run Prisma 7 migrations inside a multi-stage Docker production image. Use when: (1) `prisma migrate deploy` crashes with "Cannot resolve environment variable: DATABASE_URL" or "cannot find module" at container startup, (2) building a production Docker image that needs to run migrations before starting the server, (3) you copied only node_modules/prisma + node_modules/@prisma but the Prisma 7 CLI still fails with MODULE_NOT_FOUND at runtime, (4) Yarn 4 node-modules linker .bin/prisma symlink breaks after Docker COPY. Covers prisma.config.ts (Prisma 7), full node_modules copy requirement, and symlink recreation pattern.
code-changes-review
Perform a comprehensive code review of current uncommitted changes in a git repository. Analyzes for bugs, security vulnerabilities, best practices, DRY violations, code smells, performance issues, and areas of improvement. Use when: review changes, code review, check my code, review diff, pre-commit review, PR review, quality check. Works with any language or framework.
app-docker-deploy-with-traefik
Generate Docker and Traefik deployment configurations for any application (Node.js, Python, Go, Rust, Java). Creates Dockerfile, docker-compose.yml, docker-compose.for-traefik.yml overlay, and .env.sample with production best practices. Use when: dockerize app, containerize, add Docker, deploy with Traefik, reverse proxy setup, HTTPS/SSL, Let's Encrypt certificates, production deployment, docker-compose setup. Requires: Docker, docker-compose.
edit-article
Edit and improve articles by restructuring sections, improving clarity, and tightening prose. Use when user wants to edit, revise, or improve an article draft.
Didn't find tool you were looking for?