LoginSignup
2

More than 5 years have passed since last update.

作業中に予期せずテストデータが全て消えたので対処メモ【Docker+Rails+MySQL】

Posted at

初めまして。当方実務歴2ヵ月半のド新米プログラマーです。
予てから知識整理や備忘録としてQiitaに記事を投稿していきたいと考えていましたが、業務中にちょうどいい(?)トラブルに遭遇したので、今回初めて記事を書かせていただきます。

まだ記事の書き方もよくわからないため、知識不足な点や稚拙な表現など、読みづらい部分が多々あるかと思いますが、ご容赦ください。また、ご指摘がご指導があれば、コメントや編集リクエストにてぜひお願いいたします。

発端

既存プロジェクトを写経しながらAPI作成の勉強中、突然localhostのDBのデータが全部消えました。

原因の考察は後ほどするとして、解決までの道のりから書いていきます。

環境

OS : macOS Mojave 10.14.1
Docker : 18.09.0
Ruby : 2.4.2
Rails : 5.2.0
MySQL : 5.6
Sequel Pro : 1.1.2

対応

1.環境を再構築

ディレクトリからローカルリポジトリからDockerコンテナまで一旦全て削除し、初めから環境を作り直します。

Dockerコンテナの削除は下記を参考にしました。
Dockerイメージとコンテナの削除方法

削除し終わったら、Gitを再度クローンし、docker-compose buildでコンテナをビルドし直して、docker-compose up -dで起動。

結果:解決せず

2.レコードのdumpファイルからリストア

ここで職場の先輩にSOS。

DBのデータが格納されるディレクトリを削除してdocker-compose rm apidocker-compose rm dbからのdocker-compose buildで理論上は元に戻るということで、そのディレクトリを探すことに。
するとその途中で、プロジェクト内にDBレコードのdumpファイルが保存されていることが判明したため、方針転換してそのファイルからDBのリストア(復元)を目指すことにしました。

下記を参考に、先輩が一瞬で対応。眺める筆者。
gz圧縮されたmysqlのdumpをリストア

$ docker-compose exec db bash

root@PERSONAL:/# cd docker-entrypoint-initdb.d
root@PERSONAL:/docker-entrypoint-initdb.d# zcat [gzファイル名] | mysql -u[ユーザー名] -p chat

docker-entrypoint-initdb.dはDockerの公式イメージらしいです。
Docker MySQL公式イメージを使用してDBに初期データを流し込む

結果:普通はこれで解決…のはずなのですが、本件ではERROR 1045 (28000): Access denied for userが発生。
ユーザー権限に関するエラーらしいのですが、先輩曰く解消するのはかなり面倒そうとのことで、別の方法を探すことに。

3.Sequel Proにgzファイルを直接インポート

筆者が空っぽのSequel Proの画面を死んだ目で見ていると
「ていうかSequelで直接gzインポートできなかったっけ?」
と思い付く先輩。

探してみると確かにありました。
[メニューバー]→[ファイル]→[インポート]から、先ほどのgzファイルを選択すると…
スクリーンショット 2018-12-11 0.06.30.png
インポートが始まり…無事復元に成功しました!

4.結論

・DBのdumpは用意しておこう
・dumpがあればSequel Proに直接インポートしてしまおう
・先輩を崇めよ

原因

DBが消えた直前に行っていた作業はRSpecファイルの実行でしたので、そこに原因があると推測して調査をしてみました。

今回の件では、テストデータの自動生成を行うFactoryBotと、テスト実行後にそのテストデータを自動消去するDatabaseCleanerという2つのgemがRSpecの中で使われていました。このDatabaseCleanerが、今回テストデータが消えた原因ではないかと推測しました。

DatabaseCleanerの実装と使い所
RubyGems-DatabaseCleanerの設定内容がよくわかりません

実際の実装がこちら↓

spec_helper.rb
  config.before(:suite) do
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.clean_with(:truncation)
  end

  config.around(:each) do |example|
    DatabaseCleaner.cleaning do
      example.run
    end
  end

exampleが実行されるごとにcleaningが動き、関連するテーブルがTRUNCATEで全レコード削除される、といったところでしょうか。
ログを追ってみると、実際にDatabaseCleaner.clean_with(:truncation)の行で、ほぼ全てのテーブルに対してTRUNCATE TABLEが実行されていました…道理で。

ただ、調べた限り上記のコードは典型的な記法のようですし、そもそも実行したのは複数あるAPI中の1つのアクションに対してのRSpecで、それがなぜDBのテーブル全てを呼び出し、それらがTRUNCATEされてしまうのかまでは執筆時点では解明できませんでした。
あるいはここ以外に原因があるのかもしれませんが…力量不足。
また詳しいことが分かったら追記していこうと思います。



今後も記録しておきたい題材があればなるべく記事にしたいと思います。それでは。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2