Split dev-only user variations into db:seed:users#1574
Conversation
db/seeds.rb runs on every db:seed, including production, so it must hold only required base data. The invite/lock/confirmation-state user variations are dev test fixtures, not base data, so move them to db/seeds/dev/users.rb behind a new db:seed:users task (wired into db:seed:dev), matching how dummy.rb and payments.rb are already organized. Base users (Umberto, Amy, Aisha, Orphaned) stay in db/seeds.rb. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| namespace :seed do | ||
| desc "Generate representative sample data for development" | ||
| task dev: [ :environment, "db:seed", "db:seed:dummy", "db:seed:payments" ] | ||
| task dev: [ :environment, "db:seed", "db:seed:users", "db:seed:dummy", "db:seed:payments" ] |
There was a problem hiding this comment.
🤖 From Claude: Correction — placement of db:seed:users here is just grouping, not a hard dependency: dummy.rb/payments.rb reference only the base users (umberto/amy/aisha) created by db:seed, not these dev variations. Ordering relative to dummy/payments is cosmetic.
There was a problem hiding this comment.
Pull request overview
Moves dev-only “user variation” seed fixtures out of db/seeds.rb (which runs in production) into a dedicated dev seed file and introduces a focused db:seed:users task, aligning with the existing db:seed:dev pattern.
Changes:
- Adds
db:seed:usersand wires it into thedb:seed:devchain before dummy/payments seeds. - Introduces
db/seeds/dev/users.rbcontaining the dev-only user variation fixtures plus a targeted password reset. - Removes the dev-only user variations from
db/seeds.rb, leaving only required/base data there.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| lib/tasks/dev.rake | Adds db:seed:users task and includes it in the db:seed:dev orchestration chain. |
| db/seeds/dev/users.rb | New dev-only seed file for invite/lock/confirmation user fixtures and password reset. |
| db/seeds.rb | Removes dev-only user fixtures from production/base seeding and leaves a pointer comment. |
| desc "Seed dev-only user variations (invite/lock/confirmation states)" | ||
| task users: :environment do | ||
| load Rails.root.join("db/seeds/dev/users.rb") | ||
| end |
| user.super_user = false | ||
| user.confirmed_at = Time.current | ||
| end | ||
| unless invited.confirmed_at.present? |
There was a problem hiding this comment.
🤖 From Claude: Fixed in 5ed8689 — keyed the guard on welcome_instructions_token.present? instead of flipping the confirmed_at check. Same effect (idempotent, applies the unconfirmed state once) and matches the existing confirmed_no_pw block. Verified the user ends up confirmed_at: nil with the token set.
| user.super_user = false | ||
| user.confirmed_at = Time.current | ||
| end | ||
| unless stale_invited.confirmed_at.present? |
There was a problem hiding this comment.
🤖 From Claude: Fixed in 5ed8689 — keyed the guard on welcome_instructions_token.present? instead of flipping the confirmed_at check. Same effect (idempotent, applies the unconfirmed state once) and matches the existing confirmed_no_pw block. Verified the user ends up confirmed_at: nil with the token set.
| user.super_user = false | ||
| user.confirmed_at = Time.current | ||
| end | ||
| unless recent_invited.confirmed_at.present? |
There was a problem hiding this comment.
🤖 From Claude: Fixed in 5ed8689 — keyed the guard on welcome_instructions_token.present? instead of flipping the confirmed_at check. Same effect (idempotent, applies the unconfirmed state once) and matches the existing confirmed_no_pw block. Verified the user ends up confirmed_at: nil with the token set.
| user.super_user = false | ||
| user.confirmed_at = Time.current | ||
| end | ||
| unless invited_no_person.confirmed_at.present? |
There was a problem hiding this comment.
🤖 From Claude: Fixed in 5ed8689 — keyed the guard on welcome_instructions_token.present? instead of flipping the confirmed_at check. Same effect (idempotent, applies the unconfirmed state once) and matches the existing confirmed_no_pw block. Verified the user ends up confirmed_at: nil with the token set.
The invited.pending, stale.invite, recent.invite, and invited.noperson blocks guarded their update_columns with `unless <user>.confirmed_at.present?`, but the find_or_create_by! block had just set confirmed_at to Time.current, so the guard never fired and these users ended up confirmed rather than as pending/stale invites. Key the guard on welcome_instructions_token presence instead (matching the confirmed_no_pw block), so the invite state is applied once and stays idempotent on reseed. update_columns is retained to set the unconfirmed state without firing Devise callbacks (no confirmation email). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| user.super_user = false | ||
| user.confirmed_at = Time.current | ||
| end | ||
| unless stale_invited.welcome_instructions_token.present? |
There was a problem hiding this comment.
🤖 From Claude: Guard keys on welcome_instructions_token, not confirmed_at — find_or_create_by! just set confirmed_at to Time.current, so the old unless confirmed_at.present? never fired and these "stale/pending invite" users ended up confirmed. Token presence is the real "invite already set up" marker, so this runs once and stays idempotent.
What is the goal of this PR and why is this important?
db/seeds.rbruns on everydb:seed, including production, so it must hold only required base data — never test fixtures.invited.pending,confirmed.nopassword,locked.user,never.invited,stale.invite,recent.invite,orphan.uninvited,invited.noperson) are dev-only fixtures for exercising login/invite edge cases. They were living indb/seeds.rband so ran in production.dummy.rbandpayments.rb: dev sample data lives underdb/seeds/dev/behind focuseddb:seed:*tasks.How did you approach the change?
db/seeds/dev/users.rb, re-resolving the admin viafind_by!sincedb:seedruns first.db:seed:usersand wired it into thedb:seed:devchain:db:seed→db:seed:users→db:seed:dummy→db:seed:payments(the dev-user position is grouping, not a hard dependency — dummy/payments reference only the base users fromdb:seed).db/seeds.rbnow seeds only the required base users (Umberto, Amy, Aisha, Orphaned) plus their password reset; everything else (WindowsTypes, FormBuilders, OrganizationStatuses, Organization, Sectors, CategoryTypes/Categories, etc.) is legit base data and stays.dev/users.rbso they remain loggable-in after a reseed without touching other users.Bug fix included
invited.pending,stale.invite,recent.invite, andinvited.nopersonguarded theirupdate_columnswithunless <user>.confirmed_at.present?— butfind_or_create_by!had just setconfirmed_attoTime.current, so the guard never fired and these users ended up confirmed instead of pending/stale invites.welcome_instructions_tokenpresence (matching theconfirmed_no_pwblock), so the unconfirmed-invite state is applied once and stays idempotent.update_columnsis retained so Devise callbacks don't fire (no confirmation email).UI Testing Checklist
Anything else to add?
rake db:seed db:seed:users: base 4 + dev 8 users present, locked/no-person states preserved, and the four invite users now end upconfirmed_at: nilwith the correct invite token + sent date (3/45/1/10 days). Confirmed idempotent on re-run.🤖 Generated with Claude Code