seed と admin の二重管理問題
Rails + 任意 frontend で個人ブログを組むとき、最初に詰まるのが 「初期記事をどこに入れるか」。
選択肢:
- seed-fu — DB に直接 fixture で投入。コードと一緒にバージョン管理される
- admin で手入力 — 公開後に編集者が書く。DB の中だけに存在する
- 両方使う — seed で雛形、admin で本物に書き換える
私は最初 (3) で運用していて、seed と admin の両方が真実 という二重管理状態に陥った。
二重管理の何が困るか
具体的な症状:
make db_resetを流すと admin で書いた記事が消えるseed-fuの fixture と DB の状態がズレる- 本番環境に dev で書いた記事が乗らない / 逆もしかり
- 「この記事は seed?admin?」が判別不能
新規プロジェクトの最初の数週間で、必ずと言っていいほど踏む地雷。
解決方針: seed は「最小骨格」だけ
二重管理を避けるルール:
- seed-fu には骨格データ(admin / authors / categories / tags / api_keys)だけ入れる
- 記事は seed に入れない(demo 用の数件は OK、ただし本番では skip)
- public 記事は admin から書く
# backend/db/fixtures/03_admin_users.rb ← seed
# backend/db/fixtures/04_authors.rb ← seed
# backend/db/fixtures/05_categories.rb ← seed
# backend/db/fixtures/06_tags.rb ← seed
# backend/db/fixtures/09_api_keys.rb ← seed
# 記事は admin or Bot API のみ
これで make db_reset で消えるのは「常に再投入される骨格」だけ。記事は admin に書いたら DB に残り続ける。
demo 記事を入れたい時
最初の見栄えのために demo 記事を 5〜10 件入れたい時もある。これも seed-fu でやるが、環境変数で skip できるようにする:
# backend/db/fixtures/07_posts.rb
return if ENV['SKIP_DEMO_POSTS'] == 'true'
posts = [
{ slug: 'welcome-to-aether-echoes', ... }
]
posts.each { |p| Post.seed(:slug) { |s| s.assign_attributes(p) } }
本番デプロイ時に SKIP_DEMO_POSTS=true を渡せば、demo は入らない。
Bot API は draft 強制
オリジナル記事を増やしていくフェーズでは、Bot API 経由で draft 状態で投入 → admin で校正 → publish の運用が安定する。
# Bot::PostUpsertService
def call
payload = @payload.dup
payload[:status] = 'draft' # Bot 経由は強制 draft
Post::UpsertService.new(payload: payload, admin_user: @api_key.created_by).call
end
Bot で投入された記事も draft なので、db_reset 影響を受けない(もとから「admin で公開する」運用)。
本番デプロイ時の注意
dev で書いた記事を本番に持っていきたい時、選択肢は 2 つ:
- mysqldump → import — 単純、確実だが手作業
- API 経由で再投稿 — 自動化できるが冪等性に注意
個人サイト規模なら mysqldump で十分。月に 1 度、dev DB の posts テーブルだけ dump して本番に入れる、という運用で動く。
docker compose exec backend mysqldump -u root -proot \
--no-create-info --skip-extended-insert app_dev posts > /tmp/posts.sql
--no-create-info でテーブル定義は出さず、--skip-extended-insert で 1 行 1 INSERT に。差分管理しやすい形にする。
まとめ
content ID 管理の境界:
- seed-fu: admin / authors / categories / tags / api_keys / 必要なら demo 記事
- admin / Bot API: public 記事(draft → 校正 → published)
- db_reset: seed のみが再投入、記事は別管理
この境界を初日に引くと、二重管理の罠は避けられる。
真実の置き場所を 1 つに決める。これがコンテンツ運用の出発点。