Rails6 のちょい足しな新機能を試す82（db:seed:replant 編）

# はじめに

Rails 6 に追加されそうな新機能を試す第82段。 今回は、 `db:seed:replant` 編です。
Rails 6 では、 データをすべて削除する `db:truncate_all` ,  全部データを削除してから、 seed データを投入する `db:seed:replant` の2つのタスクが追加されました。
マルチデータベースにも対応しています。

Ruby 2.6.4, Rails 6.0.0, PostgreSQL 10.7, MySQL 8.0.17 で確認しました。

```shell
$ rails --version
Rails 6.0.0
```

今回は、 マルチデータベースを使います。 Backbone データベースは、 PostgreSQLを Library データベースは、 MySQL を使います。
Backbone に User テーブルを作ります。
Library に Book テーブルを作ります。

User と Book の seed データを作成し、タスクを実行して動作を確認します。


# プロジェクトを作る

```shell
rails new rails_sandbox
cd rails_sandbox
```

# Gemfile に pg と mysql2 を追加する

PostgreSQL と MySQL の両方のデータベースを扱うので、 `pg` と `mysql2` gem をGemfile に追加します。

```Gemfile
...
# Use mysql as the library database for Active Record
gem 'mysql2', '>= 0.4.4'
# Use postgresql as the backbone database for Active Record
gem 'pg', '>= 0.18', '< 2.0'
...
```

bundle install します。

```shell
$ bundle install
```

# config/database.yml を編集する

config/database.yml を編集して、 backbone と library の2つの接続情報を設定します。
データベースサーバの host名は、わかりやすいように postgres と mysql にしました。

```yaml:config/database.yml
default_postgresql: &default_postgresql
  adapter: postgresql
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  host: postgres
  user: <%= ENV.fetch("POSTGRES_USER") %>
  password: <%= ENV.fetch("POSTGRES_PASSWORD") %>

default_mysql: &default_mysql
  adapter: mysql2
  encoding: utf8mb4
  username: root
  password:
  host: mysql

development:
  backbone:
    <<: *default_postgresql
    database: backbone_development
  library:
    <<: *default_mysql
    database: library_development
    migrations_paths: db/library_migrate
  ...
```

# User モデルを作る

name の属性をもつ User モデルを作ります。

```shell
bin/rails g model User name
```

# Book モデルを作る

title 属性をもつ Book モデルを作ります。
このとき  `--db` オプションで `library` を指定します。

```shell
bin/rails g model Book title -db library
```

# Book モデルを編集する

`connects_to` を使って、Book モデルの接続先を library 側に変更します。

```ruby:app/models/book.rb
class Book < ApplicationRecord
  connects_to database: { writing: :library, reading: :library }
end
```

# seed データを作る

users  と books の2つの seed データを作ります。

```ruby:db/seeds.rb
User.create(
  [
    { name: 'Taro' },
    { name: 'Hanako' }
  ]
)

Book.create(
  [
    { title: 'Programming Ruby' },
    { title: 'Agile Web Development with Rails' }
  ]
)
```

# マイグレーションを実行し seed データを登録する

```shell
bin/rails db:create db:migrate db:seed
```

# rails console で確認する

`rails console` で User と Book の件数を調べてみます。

```irb
irb(main):001:0> User.count
   (0.5ms)  SELECT COUNT(*) FROM "users"
=> 2
irb(main):002:0> Book.count
   (0.2ms)  SET NAMES utf8mb4,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (6.3ms)  SELECT COUNT(*) FROM `books`
=> 2
```

# psql と mysql で確認する

psql で users テーブルのデータを確認します。

```
backbone_development=# select * from users;
 id |  name  |         created_at         |         updated_at
----+--------+----------------------------+----------------------------
  1 | Taro   | 2019-09-06 22:45:38.356429 | 2019-09-06 22:45:38.356429
  2 | Hanako | 2019-09-06 22:45:38.361014 | 2019-09-06 22:45:38.361014
(2 rows)
```

mysql で books テーブルのデータを確認します。

```
mysql> select * from books;
+----+----------------------------------+----------------------------+----------------------------+
| id | title                            | created_at                 | updated_at                 |
+----+----------------------------------+----------------------------+----------------------------+
|  1 | Programming Ruby                 | 2019-09-06 22:45:38.378629 | 2019-09-06 22:45:38.378629 |
|  2 | Agile Web Development with Rails | 2019-09-06 22:45:38.395576 | 2019-09-06 22:45:38.395576 |
+----+----------------------------------+----------------------------+----------------------------+
2 rows in set (0.00 sec)
```

# もう一度 db:seed を実行する

ここで、もう一度 db:seed を実行します。

```shell
$ bin/rails db:seed
```

User と Book の件数は増えます。

```irb
irb(main):003:0> User.count
   (0.8ms)  SELECT COUNT(*) FROM "users"
=> 4
irb(main):004:0> Book.count
   (3.1ms)  SELECT COUNT(*) FROM `books`
=> 4
```

psql と mysql で確認しても同様に件数が増えています。


psql:

```
backbone_development=# select * from users;
 id |  name  |         created_at         |         updated_at
----+--------+----------------------------+----------------------------
  1 | Taro   | 2019-09-06 22:45:38.356429 | 2019-09-06 22:45:38.356429
  2 | Hanako | 2019-09-06 22:45:38.361014 | 2019-09-06 22:45:38.361014
  3 | Taro   | 2019-09-06 22:58:19.359173 | 2019-09-06 22:58:19.359173
  4 | Hanako | 2019-09-06 22:58:19.365323 | 2019-09-06 22:58:19.365323
(4 rows)
```

mysql:

```
mysql> select * from books;
+----+----------------------------------+----------------------------+----------------------------+
| id | title                            | created_at                 | updated_at                 |
+----+----------------------------------+----------------------------+----------------------------+
|  1 | Programming Ruby                 | 2019-09-06 22:45:38.378629 | 2019-09-06 22:45:38.378629 |
|  2 | Agile Web Development with Rails | 2019-09-06 22:45:38.395576 | 2019-09-06 22:45:38.395576 |
|  3 | Programming Ruby                 | 2019-09-06 22:58:19.382802 | 2019-09-06 22:58:19.382802 |
|  4 | Agile Web Development with Rails | 2019-09-06 22:58:19.397899 | 2019-09-06 22:58:19.397899 |
+----+----------------------------------+----------------------------+----------------------------+
4 rows in set (0.00 sec)
```

# db:seed:replant を試す

`db:seed:replant` を試してみましょう。

```shell
$ bin/rails db:seed:replant
```

rails console で確認するとデータは増えずに2件ずつとなっています。

```irb
irb(main):005:0> User.count
   (1.0ms)  SELECT COUNT(*) FROM "users"
=> 2
irb(main):006:0> Book.count
   (5.0ms)  SELECT COUNT(*) FROM `books`
=> 2
```

psql と mysql でも確認します。

psql:

```
backbone_development=# select * from users;
 id |  name  |         created_at         |         updated_at
----+--------+----------------------------+----------------------------
  5 | Taro   | 2019-09-06 23:05:17.516149 | 2019-09-06 23:05:17.516149
  6 | Hanako | 2019-09-06 23:05:17.524706 | 2019-09-06 23:05:17.524706
(2 rows)
```

mysql:

```
mysql> select * from books;
+----+----------------------------------+----------------------------+----------------------------+
| id | title                            | created_at                 | updated_at                 |
+----+----------------------------------+----------------------------+----------------------------+
|  1 | Programming Ruby                 | 2019-09-06 23:05:17.573838 | 2019-09-06 23:05:17.573838 |
|  2 | Agile Web Development with Rails | 2019-09-06 23:05:17.585832 | 2019-09-06 23:05:17.585832 |
+----+----------------------------------+----------------------------+----------------------------+
2 rows in set (0.00 sec)
```

# db:truncate_all を実行する

最後に db:truncate_all を実行してみます。

```shell
$ bin/rails db:truncate_all
```

rails console で確認すると、データが削除されていることがわかります。

```irb
irb(main):007:0> User.count
   (1.1ms)  SELECT COUNT(*) FROM "users"
=> 0
irb(main):008:0> Book.count
   (2.4ms)  SELECT COUNT(*) FROM `books`
=> 0
```

# sqlite3

sqlite3 には、 truncate が存在しないため、代わりに、 `DELETE FROM (テーブル名)` を使っています。

# 試したソース

試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try082_db_seed_replant

# 参考情報

* [What is new in Rails 6.0](https://bogdanvlviv.com/posts/ruby/rails/what-is-new-in-rails-6_0.html)
* [Allow `truncate` for SQLite3 adapter and add `rails db:seed:replant`](https://github.com/rails/rails/pull/34779)