PostgreSQLのインストールからRailsでのDB変更まで

お疲れ様です。RailsのPostgreSQL環境再構築の項です。

RailsのDBをPostgreSQLに変更するとき
以下の点に留意して下さい。

- 新しい情報が少ない
- 情報に統一性がない
- ```rails new``` からやり直す方がストレスは少ない

上記を踏まえ, 止むを得ずDBを変更する場面を想定して
本項をまとめました。

#ゴール
- Railsの開発環境で, PostgreSQLを使えるようにする
- PostgreSQLにSeedデータを挿入する

#前提
- Mac OS Mojave 10.14.3
- Homebrewを使える
    - 解説資料 : [Homebrewのインストールから操作まで](https://qiita.com/krtsatoqiita/items/ba567acacb93a7a02dd9)
- Rails 5.2 を使える
    - Model, validates, View, Controllerは作成済み
- Herokuへのデプロイまではカバーしない

#やること
1. PostgreSQLとは
2. PostgreSQLインストール
3. PostgreSQLセットアップ
4. Railsに適用する

##1. PostgreSQLとは
![postgres.png](https://qiita-image-store.s3.amazonaws.com/0/288484/33a5f87c-7e9e-6310-03ae-114d3ceed6ee.png)

- 高機能, 堅牢性を追求したRDB
- 標準SQLに比較的準拠している
- 詳細資料
    - [【DBまとめ】MySQLからPostgreSQL,SQLiteまで](https://qiita.com/kenju/items/cde7f5b4f4cfacf749ed#postgresql) 
    - [MySQLユーザーがPostgreSQLを使う事になった時の比較まとめ](https://qiita.com/motsat/items/bb72af915c7bf12559f3#まとめ)

##2. PostgreSQLインストール
<details><summary>参考 : インストール時のHEADオプションでエラー発生</summary><div>
 
```terminal:terminal
$ brew info postgresql
postgresql: stable 11.2 (bottled), HEAD

$ brew install postgresql --HEAD # HEADバージョン
...
configure: error: header file <perl.h> is required for Perl
READ THIS: https://docs.brew.sh/Troubleshooting
```

- 本題から外れるためエラーの原因は追求せず
- HomebrewがインストールできるFormulaを確認
  - FormulaとはHomebrewが管理するパッケージ

```terminal:terminal
$ brew search postgresql
==> Formulae # HEADバージョンの11.2は未登録?
postgresql       postgresql@10       postgresql@9.4
postgresql@9.5   postgresql@9.6
```
</div></details>

```postgresql``` を選ぶと最新安定版を指定できる

```terminal:terminal
$ brew install postgresql

$ postgres --version
postgres (PostgreSQL) 11.2 
```
バージョン11.2をインストール出来た

##3. PostgreSQLセットアップ
3-1. PATH確認
3-2. PGDATA設定
3-3. ユーザ作成
3-4. DB作成
3-5. DB起動確認
3-6. DB権限付与

###3-1. PATH確認
- インストール後のコマンド操作では ```psql``` を使う
- DB名は ```postgres``` となっている

```terminal:terminal
$ which postgres # デフォルトDBのPATH
/usr/local/Cellar/postgresql/11.2/bin/postgres
```

###3-2. PGDATA設定
- 起動時の設定事項の参照場所を明記してコマンドを短縮
- エディタ(VSCode)起動 ```$ code ~/.bash_profile```

```bash:.bash_profile
# PostgreSQL 追加
export PGDATA=/usr/local/var/postgres
```
ターミナルで変更を反映 ```$ source ~/.bash_profile```

###3-3. ユーザ作成
- アプリ名をユーザとして定義
- [4-3. config/database.yml補完](https://qiita.com/drafts/4565051608a63f11b316/edit#4-3-configdatabaseyml補完) に対する準備

```terminal:terminal
$ createuser MyApp
$ createuser MyApp -P # パスワードが必要な場合
```

###3-4. DB作成
- [3-3. ユーザ作成](https://qiita.com/drafts/4565051608a63f11b316/edit#3-3-ユーザ作成) のユーザをオーナに設定
- デフォルトでは, Macのログインユーザがオーナになる

```terminal:terminal
$ createdb MyApp_development -O MyApp
$ createdb MyApp_test -O MyApp
```

```$ createdb MyApp_production``` は
HerokuのPostgreSQLを使用するので実行せず


###3-5. DB起動確認
まずユーザを表示する

- ```psql```     : PostgreSQLをターミナルで操作
- ```-c```       : 実行するコマンド (--command='コマンド')
- ```postgres``` : DB名を指定

```terminal:terminal
$ brew services start postgresql # DB起動
==> Successfully started `postgresql` ...

$ psql -c 'select * from pg_user' postgres
 usename  | usesysid | ... | usesuper | ...
----------+----------+ ... +----------+ ...
 Macユーザ |       10 | ... | t        | ...
 MyApp    |    16390 | ... | f        | ...
```

次にDBを表示する

- ```-l``` : DBの一覧表示
- ```template0/1``` : DB作成時に素材となるため削除しない

```terminal:terminal
$ psql -l
        Name       |   Owner  | Encoding | ...
-------------------+----------+----------+ ...
 MyApp_development | MyApp    | UTF8     | ...
 MyApp_test        | MyApp    | UTF8     | ...
 postgres          | Macユーザ | UTF8     | ...
 template0         | Macユーザ | UTF8     | ...
 template1         | Macユーザ | UTF8     | ...

$ brew services stop postgresql # DB終了
==> Successfully stopped `postgresql` ...
```

<details><summary>参考 : ユーザ・DBを削除する場合</summary><div>

```terminal:terminal
$ dropuser ユーザ名
$ dropdb DB名
```
</div></details>

###3-6. DB権限付与
- [4-3. config/database.yml補完](https://qiita.com/drafts/4565051608a63f11b316/edit#4-3-configdatabaseyml補完) に対する準備
  - 4-3. で ```username:``` のユーザと, ここで権限付与されるユーザが一致
- [3-5. DB起動確認](https://qiita.com/drafts/4565051608a63f11b316/edit#3-5-db起動確認) で権限の確認をする
  - ```MyApp``` において ```usesuper: t``` にしたい
  - 既に ```usesuper``` を持つ ```Macユーザ``` を利用して ```MyApp``` に権限付与
- -U : ユーザ名を指定してDBに接続
   
```terminal:terminal
$ brew services start postgresql

$ psql -U Macユーザ MyApp_development
psql (11.2)
Type "help" for help.

MyApp_development=# \du # ユーザ一覧
 Role name |   Attributes   | ...
-----------+----------------+ ...
 Macユーザ  | Superuser, ... | ...
 MyApp     |                | ...

MyApp_development=# ALTER ROLE "MyApp" WITH Superuser;
ALTER ROLE
rails_dev=# \du

 Role name |   Attributes   | ...
-----------+----------------+ ...
 Macユーザ  | Superuser, ... | ...
 MyApp     | Superuser      | ...

MyApp_development=# \q # 操作終了

$ brew services stop postgresql
```

```Macユーザ``` が ```MyApp``` に ```Superuser``` 権限を付与した

##4. Railsに適用する
4-1. Gemfile変更
4-2. config/database.yml比較
4-3. config/database.yml補完
4-4. DB動作確認

###4-1. Gemfile変更
```ruby:Gemfile
# gem 'sqlite3', '~> 1.3.6' 変更
gem 'pg'
```

変更後 ```bundle install``` する

###4-2. config/database.yml比較
まず ```rails new``` で ```-d postgresql``` したときの
config/database.ymlと比較して, 必要箇所を追加・変更する

```yaml:database.yml
default: &default
  # adapter: sqlite3 変更
  adapter: postgresql
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000
  encoding: unicode # 追加

development:
  <<: *default
  # database: db/development.sqlite3 変更
  database: MyApp_development

test:
  <<: *default
  # database: db/test.sqlite3 変更
  database: MyApp_test

# Herokuデプロイ時に再度見直す
production:
  <<: *default
  # database: db/production.sqlite3 変更
  database: MyApp_production
  username: MyApp # 追加
  password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %> # 追加
```

<details><summary>比較： ```rails new``` でPostgreSQLを指定した場合</summary><div>

```terminal:terminal
$ bundle exec rails new MyApp -d postgresql
```
```yaml:database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default
  database: MyApp_development

test:
  <<: *default
  database: MyApp_test

production:
  <<: *default
  database: MyApp_production
  username: MyApp
  password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %>
```
</div></details>

###4-3. config/database.yml補完
上記の変更だけではコネクションエラーが発生するため
config/database.ymlに追記する

- default:
    - ```username``` : [3-3. ユーザ作成](https://qiita.com/drafts/4565051608a63f11b316/edit#3-3-ユーザ作成) のユーザ
    - ```password``` : ユーザのパスワード, 未設定の場合は空欄
    - ```host``` : localhostのポート番号は不要
- production:
    - ```database``` : Herokuへのデプロイを考慮して削除
    - ```username``` : default内に追記したので削除

```yaml:database.yml
default: &default
  # ...
  username: MyApp # 追加
  password:       # 追加
  host: localhost # 追加

development:
  <<: *default
  # ...

test:
  <<: *default
  # ...

production:
  <<: *default
  # ...
  # database: MyApp_production 削除
  # username: MyApp 削除
```

<details><summary>参考 : 最終的なconfig/database.yml</summary><div>

```yaml:database.yml
default: &default
  adapter: postgresql
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000
  encoding: utf8
  username: MyApp
  password:
  host: localhost

development:
  <<: *default
  database: MyApp_development

test:
  <<: *default
  database: MyApp_test

# Herokuへのデプロイに関しては別記事を参照して下さい
production:
  <<: *default
  password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %>
```
</div></details>

###4-4. DB動作確認
- 動作確認のため, db/seeds.rbにSeedデータを記述
- ```create!()``` : レコード作成時のエラーを通知

```ruby:seeds.rb
モデル名.create!(
  name: "my name",
  content: "hello!",
)
```

- ```db:migrate:reset``` : DB削除 -> DB再度作成 -> db:migrate順次実行
- ```db:seed``` : Seedデータを反映
- デフォルトでは ```development``` に適用
    - テスト環境への適用には, オプション ```RAILS_ENV=test``` を指定

```terminal:terminal
$ bundle exec rails db:migrate:reset
$ bundle exec rails db:seed
```

Seedデータを確認

<details><summary>参考 : PostgeSQLの整形</summary><div>

- 縦に整列する
- フィールドがnullの場合, ```null``` と表記する
- エディタ(VSCode)起動 ```$ code ~/.psqlrc```

```bash:.psqlrc
\x auto
\pset null null
```

ターミナルで変更を反映 ```$ source ~/.psqlrc```
</div></details>

```terminal:terminal
$ bundle exec rails db
...
MyApp_development=# SELECT * FROM "モデルで作成されたテーブル名";
-[ RECORD 1 ]----------------------
id      | 1
name    | my name
content | hello!
...

MyApp_development=# \q
```

- foremanでwebpack起動 -> localhost接続
- 開発環境によっては ```rails s``` でOK

```terminal:terminal
$ bundle exec foreman start
```

この辺りは, 各開発環境(API, Webpack等)やControllerに応じて
DB -> フロント での表示を確認しましょう。

お疲れ様でした。
この項・完