Skip to content

Split dev-only user variations into db:seed:users#1574

Merged
maebeale merged 2 commits into
mainfrom
maebeale/split-seeds-into-rake-tasks
Jun 6, 2026
Merged

Split dev-only user variations into db:seed:users#1574
maebeale merged 2 commits into
mainfrom
maebeale/split-seeds-into-rake-tasks

Conversation

@maebeale

@maebeale maebeale commented Jun 6, 2026

Copy link
Copy Markdown
Collaborator

What is the goal of this PR and why is this important?

  • db/seeds.rb runs on every db:seed, including production, so it must hold only required base data — never test fixtures.
  • The invite/lock/confirmation-state user variations (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 in db/seeds.rb and so ran in production.
  • Follows the same pattern Consolidate dev payment seeds into db:seed:dev #1573 (now merged) established for dummy.rb and payments.rb: dev sample data lives under db/seeds/dev/ behind focused db:seed:* tasks.

How did you approach the change?

  • Moved the 8 user variations to db/seeds/dev/users.rb, re-resolving the admin via find_by! since db:seed runs first.
  • Added db:seed:users and wired it into the db:seed:dev chain: db:seeddb:seed:usersdb:seed:dummydb:seed:payments (the dev-user position is grouping, not a hard dependency — dummy/payments reference only the base users from db:seed).
  • db/seeds.rb now 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.
  • Added a parity password-reset for the dev emails inside dev/users.rb so they remain loggable-in after a reseed without touching other users.

Bug fix included

  • invited.pending, stale.invite, recent.invite, and invited.noperson guarded their update_columns with unless <user>.confirmed_at.present? — but find_or_create_by! had just set confirmed_at to Time.current, so the guard never fired and these users ended up confirmed instead of pending/stale invites.
  • Fixed by keying the guard on welcome_instructions_token presence (matching the confirmed_no_pw block), so the unconfirmed-invite state is applied once and stays idempotent. update_columns is retained so Devise callbacks don't fire (no confirmation email).

UI Testing Checklist

  • No UI changes — seed/rake refactor only.

Anything else to add?

  • Verified end-to-end with rake db:seed db:seed:users: base 4 + dev 8 users present, locked/no-person states preserved, and the four invite users now end up confirmed_at: nil with the correct invite token + sent date (3/45/1/10 days). Confirmed idempotent on re-run.
  • Builds on Consolidate dev payment seeds into db:seed:dev #1573 (merged to main); rebased onto current main.

🤖 Generated with Claude Code

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>
Copilot AI review requested due to automatic review settings June 6, 2026 21:04
Comment thread lib/tasks/dev.rake
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" ]

@maebeale maebeale Jun 6, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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.

@maebeale maebeale marked this pull request as ready for review June 6, 2026 21:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:users and wires it into the db:seed:dev chain before dummy/payments seeds.
  • Introduces db/seeds/dev/users.rb containing 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.

Comment thread lib/tasks/dev.rake
Comment on lines +6 to +9
desc "Seed dev-only user variations (invite/lock/confirmation states)"
task users: :environment do
load Rails.root.join("db/seeds/dev/users.rb")
end
Comment thread db/seeds/dev/users.rb Outdated
user.super_user = false
user.confirmed_at = Time.current
end
unless invited.confirmed_at.present?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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.

Comment thread db/seeds/dev/users.rb Outdated
user.super_user = false
user.confirmed_at = Time.current
end
unless stale_invited.confirmed_at.present?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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.

Comment thread db/seeds/dev/users.rb Outdated
user.super_user = false
user.confirmed_at = Time.current
end
unless recent_invited.confirmed_at.present?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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.

Comment thread db/seeds/dev/users.rb Outdated
user.super_user = false
user.confirmed_at = Time.current
end
unless invited_no_person.confirmed_at.present?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 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>
Comment thread db/seeds/dev/users.rb
user.super_user = false
user.confirmed_at = Time.current
end
unless stale_invited.welcome_instructions_token.present?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: Guard keys on welcome_instructions_token, not confirmed_atfind_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.

@maebeale maebeale merged commit 052e2b2 into main Jun 6, 2026
3 checks passed
@maebeale maebeale deleted the maebeale/split-seeds-into-rake-tasks branch June 6, 2026 21:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants