Skip to content

db/schema.rb 가 gitignore + 자동 덤프라 스키마 손상·드리프트가 diff 로 잡히지 않음 #934

Description

@stadia

요약

db/schema.rb.gitignore 대상(.gitignore:44)이라 각 환경마다 로컬 덤프만 존재한다. Rails 는 마이그레이션 실행 시 이 파일을 자동으로 덮어쓰므로, DB 스키마가 손상되면 그 손상이 조용히 schema.rb 에 기록되고 git status 는 끝까지 깨끗하다.

실제로 발생한 사례

#846 작업 중 마이그레이션 검증을 위해 아래를 실행했다.

RAILS_ENV=test rails db:migrate:redo:primary VERSION=20260502235353

이 마이그레이션은 add_column :sites, :url 을 하는데, down 의 remove_column나중 마이그레이션(20260524104358)이 만든 부분 unique 인덱스 index_sites_unique_url_for_rss 를 CASCADE 로 함께 삭제했다. 재-up 은 컬럼만 되돌리므로 인덱스는 복구되지 않는다.

그 직후 Rails 가 손상된 DB 를 db/schema.rb 에 자동 덤프하면서 인덱스 정의 줄이 사라졌다. gitignore 대상이라 diff 에 아무것도 안 나타났다.

더 나쁜 건 그 다음이다. test 환경의 db:migrate 는 schema.rb 가 있으면 마이그레이션을 실행하지 않고 schema.rb 를 로드한다. 그래서 DB 를 drop/create 하고 다시 마이그레이션해도 손상 상태가 계속 재현됐고, 마치 마이그레이션 자체의 버그처럼 보였다.

schema.rb 를 치우고 마이그레이션 45개를 실제로 실행시켜야만 진상이 드러났다 — 마이그레이션은 정상이며 인덱스를 제대로 만든다.

파생 확인 — 마이그레이션 산출물과 실제 DB 의 드리프트

같은 방식으로 "마이그레이션을 실제로 돌린 결과" 와 프로덕션형 덤프를 비교하니 차이가 있었다.

대상 프로덕션형 DB 마이그레이션 산출물
posts index_posts_on_depth 있음 없음
users.name limit: 50 limit 없음
users.encrypted_password default: "" default 없음
articles index_articles_on_related_and_published_at index_articles_on_is_related_and_published_at
articles 없음 index_articles_on_site_id_and_published_at
taggings idx_on_taggable_id_taggable_type_tagger_id_context_72eb419f98 taggings_idy

프로덕션에 수동 DDL 이 들어간 것인지, 적용 후 마이그레이션 파일이 수정된 것인지는 이번 조사로 구분하지 못했다. schema.rb 가 버전 관리되고 있었다면 어느 커밋에서 갈라졌는지 diff 로 추적 가능했을 문제다.

영향

  • 스키마 손상(인덱스·제약 유실)이 리뷰에서 걸러지지 않는다
  • 환경 간 스키마 드리프트를 탐지할 방법이 없다
  • db:migrate 가 실제로 마이그레이션을 돌렸는지 schema 를 로드했는지 구분이 어려워 디버깅이 오래 걸린다

제안

  1. db/schema.rb.gitignore 에서 제거하고 커밋 대상으로 되돌린다. 드리프트가 PR diff 에 드러난다.
  2. 또는 config.active_record.schema_format = :sql 로 전환해 db/structure.sql 을 커밋한다. ra_news 스키마·부분 인덱스·hairtrigger 트리거까지 정확히 표현되므로 이 프로젝트 구성에는 이쪽이 더 맞을 수 있다.
  3. 관례 문서화: 컬럼 추가 마이그레이션에 db:migrate:redo 를 쓰면 이후 마이그레이션이 만든 인덱스가 CASCADE 삭제된다. 검증은 db:dropdb:create → 전체 db:migrate 로 한다.

관련: #846, #933

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingrubyPull requests that update ruby code

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions