Skip to main content

models

ActiveRecord models, migrations and schema — tables, columns, indexes, associations, validations, scopes — with PostgreSQL production safety. Use when adding or changing a table or a model, or when reviewing a migration before it ships.

معلومات المصدر

المستودع
zoolutions/claude-plugins
آخر نشاط في المصدر
١٧ أكتوبر ٢٠٢٦ في ١٨:٥٩
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٢
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
models
description
ActiveRecord models, migrations and schema — tables, columns, indexes, associations, validations, scopes — with PostgreSQL production safety. Use when adding or changing a table or a model, or when reviewing a migration before it ships.
argument-hint
model, migration or schema task; or a migration file to review
allowed-tools
Bash(*), Read, Write, Edit, Glob, Grep, Skill
model
sonnet
# Models: $ARGUMENTS **Read the repository first.** `AGENTS.md` → `## Workflow`: **Tenant**, **Migrations**, **Verify**. A missing label means "none". Write the model spec first (/flow:tdd). Query speed is /rails-app:database. ## Migrations - Generate them: `bin/rails g migration AddFooToBars foo:string`. Never type a filename with a round time (`…0000`, `…1500`, `…3000`, `…4500`): two branches cut the same day land on one version: in one tree `db:migrate` raises `DuplicateMigrationVersionError`, and where one branch's migration already ran, the other is treated as applied and silently skipped. Writing the file yourself: version from `date -u +%Y%m%d%H%M%S`. Before merge, confirm main has no file with that version: `git ls-tree --name-only origin/main db/migrate/ | grep <version>`. - Run up, down, up locally. The `db/schema.rb` diff holds only what you meant. - Workflow → Migrations names the safety gem and the version check. Fix what the gem flags; a `safety_assured` needs a comment saying why the operation is safe on this table's size. ## Production safety (PostgreSQL) | Change | Unsafe | Safe | |---|---|---| | Index on an existing table | plain `add_index` | `disable_ddl_transaction!` + `algorithm: :concurrently`. Without the first, PG refuses: `CREATE INDEX CONCURRENTLY cannot run inside a transaction block` | | Unique index | build and hope | check for duplicates first; a failed concurrent build leaves an `INVALID` index, drop it before retrying | | Reference | `add_reference …, foreign_key: true` | `disable_ddl_transaction!` + `add_reference …, index: { algorithm: :concurrently }`; `add_foreign_key …, validate: false`; `validate_foreign_key` in a follow-up migration | | NOT NULL on an existing column | `null: false` or `change_column_null` on a large table (ACCESS EXCLUSIVE + full scan) | add nullable → backfill in batches (a task or job, not the migration) → `add_check_constraint "col IS NOT NULL", validate: false` → `validate_check_constraint` → `change_column_null` (instant once a validated CHECK covers it) | | `change_column_null … validate: false` | does not exist | only `add_check_constraint` and `add_foreign_key` take `validate:` | | Volatile default (`now()`, `gen_random_uuid()`) on a big table | rewrites the table | constant default (metadata-only on PG 11+), or backfill | | `change_column_default` | expecting existing rows to change | it only affects future inserts; backfill separately | | Drop a column | `remove_column` while code still reads it | deploy `self.ignored_columns += ["col"]` first, then drop; say so in the migration | | Rename a column | `rename_column` (running instances break mid-deploy) | add new → backfill → switch reads and writes → drop old, across deploys | | Change a type | `change_column` (table rewrite) | new column + backfill + swap | | Data change | `update_all` over a large table inside a migration | batched task or job; a human-run one goes in the PR per Workflow → PR contract | | Reversibility | `remove_column :t, :c` with no type | reversible `change`, or explicit `up`/`down` | **Block the merge:** a non-concurrent index on a table you can show holds more than ~10k rows, `null: false` on an existing column with no backfill in the PR, a drop with no earlier ignore deploy, interpolated SQL. ## Models - Tenant-owned tables (Workflow → Tenant) carry the tenant FK with a foreign key and an index; composite indexes lead with it. The model `belongs_to` the tenant or reaches it through a parent that does. - Index every foreign key. Back every uniqueness validation with a unique index (the validation alone races). - Money: `decimal` with explicit `precision` and `scale`, never `float`; a currency column beside an amount on a shared table. Match the precision already in `db/schema.rb`. - Every `has_many`/`has_one` states `dependent:`. Destroying a large child set belongs in a job. - Callbacks change only the record's own state. Mail, jobs and other aggregates go in a service (/rails-app:services). - Scopes return relations: no `.to_a`, `.first` or `.pluck` inside one. - Enumerated strings: a constant list + `inclusion` validation, and a check constraint when the column is written outside the model. ## Done when - The spec covers validations, associations, scopes and every branch of new methods. - The migration ran up, down, up; the schema diff is exactly the change. - Workflow → Verify passes.
عرض على GitHub