DBは普段GUIでしか扱わないのだけれども、バックアップとリストアについて調べておく。

参考URL: How To Use The SQLite Dump Command

インストール

sudo apt install sqlite3

データベースのdump

SQLite version 3.37.2 2022-01-06 13:25:41
Enter ".help" for usage hints.
sqlite> .output db/dump.sql
sqlite> .dump
sqlite> .exit

特定のテーブルをdump

SQLite version 3.37.2 2022-01-06 13:25:41
Enter ".help" for usage hints.
sqlite> .output db/videos.sql
sqlite> .dump videos
sqlite> .exit

これひょっとすると対話型のコマンドで実行しなくてもいけるのではという気持ちもある。

特定のテーブルをdb:seedでリストア

ここからが本題である。

先程のコマンドでdump.sqlあるいはvideos.sqlが取得できた前提で実行する。 まずはテーブル全体を初期化する:

rails db:drop db:create db:migrate
Dropped database 'db/development.sqlite3'
Dropped database 'db/test.sqlite3'
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'
== 20231123063711 CreateVideos: migrating =====================================
-- create_table(:videos)
   -> 0.0020s
== 20231123063711 CreateVideos: migrated (0.0027s) ============================

つづいてseeds.rbを次のように更新する:

videos_sql = File.read("db/videos.sql")
result = ActiveRecord::Base.connection.execute(videos_sql)

rails db:seedしてみたところ残念ながらDBはリストアできていなかった。

試しにINSERT INTO行のみを実行してみたところ、レコードは1件のみ作成されていた。つまり複数行は実行できないようだ。

先程のseeds.rbを修正する:

videos_sql = File.read("db/videos.sql")
videos_sql.each_line do |sql|
  if sql.match?(/^INSERT INTO/)
    ActiveRecord::Base.connection.execute(sql)
  end
end

いい感じだ。 たまたま今回はリストア対象のテーブルが1つしかなかったのでこれで十分だ。

ただしこの方法だとテーブルとSQLのカラムが一致している必要があるため、dumpをmigrationする度に行うか、INSERT INTO table_nameINSERT INTO table_name (column, ...)と書き換える必要がある。若干不格好ではあるが、subなどのメソッドを使うとよい。

参考URL: Execute SQL-Statement from File with ActiveRecord