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

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

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

# 発端
既存プロジェクトを写経しながらAPI作成の勉強中、突然localhostのDBのデータが全部消えました。
<img src="https://qiita-image-store.s3.amazonaws.com/0/314184/07fc2999-a8dc-d31b-1cd4-f515ffa3bdd1.jpeg" width=30%>

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

# 環境
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イメージとコンテナの削除方法](https://qiita.com/tifa2chan/items/e9aa408244687a63a0ae)

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

結果：解決せず

#### 2.レコードのdumpファイルからリストア
ここで職場の先輩にSOS。

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

下記を参考に、先輩が一瞬で対応。眺める筆者。
→[gz圧縮されたmysqlのdumpをリストア]
(https://qiita.com/tukiyo3/items/84af71c5b1951a2c18e3)

```
$ 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に初期データを流し込む](https://qiita.com/drafts/7e46223f8d5f46a55edc/edit)

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

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

探してみると確かにありました。
[メニューバー]→[ファイル]→[インポート]から、先ほどのgzファイルを選択すると…
<img width="380" alt="スクリーンショット 2018-12-11 0.06.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/314184/9a55fe71-2c46-76d0-b876-ad87c666452b.png">
インポートが始まり…**無事復元に成功しました！**

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

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

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

[DatabaseCleanerの実装と使い所](https://qiita.com/shoichiimamura/items/25942acc1d1bd78ef9c3)
[RubyGems-DatabaseCleanerの設定内容がよくわかりません](https://teratail.com/questions/54294)

実際の実装がこちら↓

```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中の１つのアクションに対してのRSpecで、それがなぜDBのテーブル全てを呼び出し、それらがTRUNCATEされてしまうのかまでは執筆時点では解明できませんでした。
あるいはここ以外に原因があるのかもしれませんが…力量不足。
また詳しいことが分かったら追記していこうと思います。

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