Rails seed data
Rails + PostgreSQL test data without maintaining db/seeds.rb — schema-driven generation that never drifts.
Rails projects seed through db/seeds.rb, run by rails db:seed — a script that usually grows a list of Model.create! calls or a FactoryBot loop. It works until the schema moves and the seed does not. This guide shows the Rails-native seeding workflow, where it breaks, and the schema-driven alternative.
How Rails seeding normally works
Rails owns the schema through migrations (rails db:migrate). Seeding is db/seeds.rb, run with rails db:seed (and automatically by rails db:setup / db:reset):
# db/seeds.rb
require "faker"
50.times do
User.create!(
email: Faker::Internet.email,
name: Faker::Name.name
)
endWorks for a standalone model. The moment Order has a belongs_to :user, the seed has to create the user first and attach it — dependency order becomes something the script encodes by hand.
Where Rails seed scripts break
- Foreign keys.
Order.create!(user: user)needs a persisted parent. The seed grows ordering logic, and every added association is another line of bookkeeping. Skip it and you get a foreign-key violation — or a validation failure that is harder to trace. - Schema drift. A new non-null column, an enum, a
validatesrule — each one is a seed change.db/seeds.rbis not checked against the schema, so it silently rots until a migration surfaces the gap. - Uniform randomness. Faker produces plausible values, not production distributions. If your real
statuscolumn is 70%active, a flat loop gives you roughly a third of each — and query plans in tests stop matching production.
Schema-driven seeding with Weavori
Weavori reads the database schema — the one Rails migrated — and generates rows from it. The Rails-specific workflow:
Weavori introspects tables, foreign keys, types, and constraints, resolves dependency order (parents before children), and writes via COPY. Every generated order.user_id references a real generated user — by construction, not by association ordering.
The schema is the seed
When a Rails migration changes the schema, the generated data changes with it. There is no db/seeds.rb to update because nothing in it duplicated the schema.
Rails + Weavori in CI
The loop that keeps test databases honest:
Weavori supports API keys for headless auth, standardized exit codes, and offline license validation — CI runners on restricted networks don't phone home. Full GitHub Actions / GitLab / CircleCI / Jenkins examples in the CI/CD guide.
Which Rails seed command do you need?
| Goal | Command |
|---|---|
Run db/seeds.rb against an existing database | rails db:seed |
| Create the database, load the schema, then seed | rails db:setup |
| Drop, recreate, load the schema, then seed | rails db:reset |
| Truncate every table, then seed | rails db:seed:replant |
| Generate a production-shaped dataset with no seeds file | npx --yes @weavori/cli generate postgres://localhost:5432/mydb |
rails db:seed
rails db:seed runs db/seeds.rb. Rails supplies the runner and the ActiveRecord models; the rows come from that file, so it is the file that grows ordering logic as associations appear — and the file nobody updates after a migration.
rails db:setup
db:setup creates the database, loads the schema from db/schema.rb, and runs the seed in one pass. It is the command behind a fresh clone — which is precisely why a seed that assumes existing rows works for you and fails for the next developer who joins.
rails db:reset
db:reset drops the database, recreates it from db/schema.rb, and seeds. Running it is the honest test of whether db/seeds.rb is genuinely re-runnable from an empty schema or only works against a database somebody has already populated by hand.
rails db:seed:replant
db:seed:replant truncates every table and then runs the seed — the fastest way to reseed without dropping the schema. On Rails 4 and earlier the task is rake db:seed; Rails 5 introduced the rails prefix and kept rake as an alias.
When to keep your Rails seed
Honesty about boundaries: keep db/seeds.rb for deterministic unit-test fixtures — a known user the test asserts against. Keep Faker for single values inside tests. Weavori replaces the dataset problem: filling dev, staging, and CI databases with production-shaped, FK-intact rows.
Related guides
- PostgreSQL data generator — what a Postgres data generator does, and how it relates to fake and dummy data
- Postgres test data — the five ways to get test data, compared
- Postgres seed data generator — the tool comparison
- Postgres synthetic data — synthetic vs. mock vs. anonymized
- Django seed data and Laravel seed data — the same loop in other stacks
- Quickstart — first seed in minutes