simple_calendarを導入したRails6.0でのDB環境PostgreSQLの設定

学習メモ用です。

#解決したい問題
simple_calendarを導入したRails6.0で
開発環境DBがSQLite3、本番環境DBがPostgreSQL

本番環境において下記エラーが発生し、posts/index viewが表示されない事態に。
simple_calendarを使っているから？

`ActionView::Template::Error (PG::UndefinedColumn: ERROR:  column posts.user_id does not exist`

なぜか、本番環境ではpostsテーブルにuser_id columnだけが存在しないからうまくいかない。


と、いうことで開発環境にもPostgreSQLを適用してみる！


#開発環境
Ruby　2.7.1
Rails　6.0.3
OS macOS Catalina

## pggemのインストール

rails6.0では

```% rails db:system:change --to=postgesql```

このコマンドで簡単に移行できるよう。


以下のようにsqlite3だったところがpgに置き換わる（Gemfileも同様に置き換わる）

```config/database.yml

<!-- some long code -->

default: &default
    - adapter: sqlite3
    + adapter: postgresql
   
<!-- some long code -->
```

bundle installを実行すると                     
		
		[!] There was an error parsing `Gemfile`: You cannot specify the same gem twice with different version requirements.
		You specified: pg (~> 1.4) and pg (>= 0). Bundler cannot continue.
		
		
pggemのバージョン違いが同時にあるためbundleinstallできないとのこと
pg (~> 1.4)を残し、gem pgは削除して再度
		
		Fetching gem metadata from https://rubygems.org/.
		Could not find gem 'pg (~> 1.4)' in any of the
		gem sources listed in your Gemfile.



'pg (~> 1.4)'が見つからないとのことで、gem istall pgを実行すると
		
		Building native extensions. This could take a while...
		ERROR:  Error installing pg:
		ERROR: Failed to build gem native extension.
		
                <!-- some long code --> 

		checking for pg_config... no
		No pg_config... trying anyway. If building fails, please try again with
		--with-pg-config=/path/to/pg_config
		checking for libpq-fe.h... no
		Can't find the 'libpq-fe.h header
		*** extconf.rb failed ***
		Could not create Makefile due to some reason, probably lack of necessary

                <!-- some long code --> 

		

No pg_configとCan't find the 'libpq-fe.h header が問題っぽい。

###まずPostgreSQLインストールをできていないのでは？

    % brew install postgresql

↑これだと最新安定版をインストール可
インストール成功！

    % postgres --version postgres 
    (PostgreSQL) 13.1

gem install pgを実行

		Building native extensions. This could take a while...
		Successfully installed pg-1.2.3
		Parsing documentation for pg-1.2.3
		Installing ri documentation for pg-1.2.3
		Done installing documentation for pg after 1 seconds
		1 gem installed

		gem 'pg (~> 1.4)' in any of the　gem sources listed in your Gemfile

gem 'pg (~> 1.4)'はインストールできなかったので、指定やめた。

再度bundle install実行、無事成功!

rails sを起動してうまくいってるか確かめようとしたところ、
いつも通りyarn installをしろとのことで、

     % yarn install --check-files
		yarn install v1.22.10
		[1/4] 🔍  Resolving packages...
		[2/4] 🚚  Fetching packages...
		[3/4] 🔗  Linking dependencies...
		warning " > webpack-dev-server@3.11.0" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
		warning "webpack-dev-server > webpack-dev-middleware@3.7.2" has unmet peer dependency "webpack@^4.0.0".
		[4/4] 🔨  Building fresh packages...
		[1/3] ⠈ fsevents
		[-/3] ⠈ waiting...
		error /Users/shigeyuki_yunoki/ucms_app/node_modules/node-sass: Command failed.
		Exit code: 1

           <!-- some long code --> 

        No receipt for 'com.apple.pkg.CLTools_Executables' found at '/'.
		
		No receipt for 'com.apple.pkg.DeveloperToolsCLILeo' found at '/'.
		
		No receipt for 'com.apple.pkg.DeveloperToolsCLI' found at '/'.
		
		gyp: No Xcode or CLT version detected!
		gyp ERR! configure error 
		gyp ERR! stack Error: `gyp` failed with exit code: 1
		gyp ERR! stack     at ChildProcess.onCpExit (/Users/shigeyuki_yunoki/ucms_app/node_modules/node-gyp/lib/configure.js:345:16)
		gyp ERR! stack     at ChildProcess.emit (node:events:376:20)
		gyp ERR! stack     at Process.ChildProcess._handle.onexit (node:internal/child_process:284:12)
		gyp ERR! System Darwin 19.6.0
		gyp ERR! command "/usr/local/Cellar/node/15.5.0/bin/node" "/Users/shigeyuki_yunoki/ucms_app/node_modules/node-gyp/bin/node-gyp.js" "rebuild" "--verbose" "--libsass_ext=" "--libsass_cflags=" "--libsass_ldflags=" "--libsass_library="
	 　　gyp ERR! cwd /Users/shigeyuki_yunoki/ucms_app/node_modules/node-sass
	 　　gyp ERR! node -v v15.5.0
        gyp ERR! node-gyp -v v3.8.0
	 　　gyp ERR! not ok 
	 　　Build failed with error code: 1

       <!-- some long code --> 

###yarnにおけるXcodeとCLTをインストール

    gyp: No Xcode or CLT version detected!
これが問題らしい

    % pkgutil --packages | grep CL
CLToolsを確認するが何も出力されず、


Xcodeのバージョンの問題だと思われるため、再インストール
    
    % sudo rm -rf $(xcode-select -print-path)
    Password:

macのパスワードを入力したものの反応なし

    % sudo rm -rf /Library/Developer/CommandLineTools
Xcode Command Line Toolsのあるディレクトリを削除することでアンインストールする。
こちらは実行していないが、最終的にうまくいったので、Xcodeはインストールしていなかったものと思われ。

    % xcode-select --install
コマンド上でXcode Command Line Toolsをインストール。

    xcode-select: error: command line tools are already installed, use "Software Update" to install updates

インストール済みだと上記になる
         
Xcodeをインストールしてから実行すると以下が出力された。

	% pkgutil --packages | grep CL
		com.apple.pkg.CLTools_Executables
		com.apple.pkg.CLTools_SDK_macOS110
		com.apple.pkg.CLTools_SDK_macOS1015
		com.apple.pkg.CLTools_macOS_SDK
		
	% pkgutil --pkg-info com.apple.pkg.CLTools_Executables
		package-id: com.apple.pkg.CLTools_Executables
		version: 12.3.0.0.1.1607026830
		volume: /
		location: /
		install-time: 1609036372
		groups: com.apple.FindSystemFiles.pkg-group


No Xcode or CLT versionは解決した！

    % yarn install --check-files
       yarn install v1.22.10
		[1/4] 🔍  Resolving packages...
		[2/4] 🚚  Fetching packages...
		[3/4] 🔗  Linking dependencies...
		warning " > webpack-dev-server@3.11.0" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
		warning "webpack-dev-server > webpack-dev-middleware@3.7.2" has unmet peer dependency "webpack@^4.0.0".
		[4/4] 🔨  Building fresh packages...
		✨  Done in 184.82s.

yarn install成功！

###PGSQLサーバーの起動

rails sを起動してみる

	　　PG::ConnectionBad (could not connect to server: No such file or directory
			Is the server running locally and accepting
			connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
		):

PGSQLサーバーが動いていないということらしい

	% brew service start postgresql
	Error: Unknown command: service

<!---->
    % brew tap homebrew/services
 このコマンドでservicesのような外部コマンドを取り込めるとのこと
 
		% brew services start postgresql
		==> Successfully started `postgresql` 

PGSQLサーバーが動いた！

###PGSQLでのDBの作成と権限付与

rails s起動すると

    ActiveRecord::NoDatabaseError
    FATAL: database "ucms_app_development" does not exist

DBが存在していない

このページで最初にあげた`config/database.yml`の詳しい中身はこちら。


```config/database.yml
       
		default: &default
		- adapter: sqlite3 
		+ adapter: postgresql　
		username: ucms_app　追記
		password:　追記
		host: localhost　追記
		encoding: utf8
		pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
		timeout: 5000
		
		development:
		<<: *default
		- database: db/development.sqlite3
		+ database: ucms_app_development
		
		test:
		<<: *default
		- database: db/test.sqlite3
		+ database: ucms_app_test
		
		production:
		<<: *default
        - database: db/production.sqlite3
		# database: ucms_app_production  Herokuへのデプロイを考慮して削除
		# username: ucms_app default内に追記したので削除
		password: <%= ENV['UCMS_APP_DATABASE_PASSWORD'] %>
```
下記コマンドにより、PGSQLのDB設定にpgが導入され、sqliteが削除された。
更に設定を追記したのが上記。

    % rails db:system:change --to=postgesql

これでDBが作られたわけではない。

    % psql -l                                   
               

####PGSQLのDB表示する
  List of databases

   Name    |      Owner       | Encoding | Collate | Ctype |           Access privileges           
-----------+------------------+----------+---------+-------+---------------------------------------
 postgres  | (macユーザー） 　　　| UTF8     | C       | C     | 
 template0 | (macユーザー）　　　 | UTF8     | C       | C     | =c/(macユーザー）                  
 template1 | (macユーザー）　　　 | UTF8     | C       | C     | =c/(macユーザー）                  
(3 rows)

"(macユーザー）"はユーザー毎に異なる。

####DBを作成する


    % createdb ucms_app_development
    % createdb ucms_app_test 
 % createdb ucms_app_productionはherokuで本番環境を扱うため不要

<!---->
    % psql -l

List of databases

         Name         |      Owner       | Encoding | Collate | Ctype |           Access privileges           
----------------------+------------------+----------+---------+-------+---------------------------------------
 postgres             | (macユーザー）      | UTF8     | C       | C     | 
 template0            | (macユーザー）      | UTF8     | C       | C     | =c/(macユーザー）                       
 template1            | (macユーザー）      | UTF8     | C       | C     | =c/(macユーザー）        
 ucms_app_development | (macユーザー）      | UTF8     | C       | C     | 
 ucms_app_test        | (macユーザー）      | UTF8     | C       | C     | 
(5 rows)

    % psql -c 'select * from pg_user' postgres
<!---->
     usename      | usesysid | usecreatedb | usesuper | userepl | usebypassrls |  passwd  | valuntil | useconfig 
------------------+----------+-------------+----------+---------+--------------+----------+----------+-----------
(macユーザー）        |       10 | t           | t        | t       | t            | ******** |          | 
(1 row)

####ユーザーを作成する
    % createuser ucms_app
####'(macユーザー）'でpsqlを操作する
    % psql -U (macユーザー） ucms_app_development

     ucms_app_development=# \du　＃ユーザー一覧を表示
<!---->
List of roles

	Role name     |                         Attributes                         | Member of 
------------------+------------------------------------------------------------+-----------
(macユーザー）      | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
ucms_app         |                                                            | {}

	 ucms_app_development=# ALTER ROLE "ucms_app" WITH Superuser;　
     ALTER ROLE　#⬆️(macユーザー）がucms_appに権限を付与。
     ucms_app_development=# \du
<!---->

List of roles

	Role name     |                         Attributes                         | Member of 
------------------+------------------------------------------------------------+-----------
(macユーザー）      | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
ucms_app         | Superuser                                                  | {}


`config/database.yml`の`username:`と一致させる必要がある。

    % psql -c 'select * from pg_user' postgres     
<!---->

	usename      | usesysid | usecreatedb | usesuper | userepl | usebypassrls |  passwd  | valuntil | useconfig 
------------------+----------+-------------+----------+---------+--------------+----------+----------+-----------
(macユーザー） |       10 | t           | t        | t       | t            | ******** |          | 
ucms_app         |    16384 | f           | t        | f       | f            | ******** |          | 
(2 rows)

    % psql -l
<!---->


List of databases

         Name         |      Owner       | Encoding | Collate | Ctype |           Access privileges           
----------------------+------------------+----------+---------+-------+---------------------------------------
 postgres             | (macユーザー） | UTF8     | C       | C     | 
 template0            | (macユーザー） | UTF8     | C       | C     | =c/(macユーザー）                  +
                      |                  |          |         |       | (macユーザー）=CTc/(macユーザー）
 template1            | (macユーザー） | UTF8     | C       | C     | =c/(macユーザー）                  +
                      |                  |          |         |       | (macユーザー）=CTc/(macユーザー）
 ucms_app_development | ucms_app         | UTF8     | C       | C     | 
 ucms_app_test        | ucms_app         | UTF8     | C       | C     | 
 ucms_app_test-0      | ucms_app         | UTF8     | C       | C     | 
 ucms_app_test-1      | ucms_app         | UTF8     | C       | C     | 
(7 rows)

    % createdb ucms_app_development
    % createdb ucms_app_test 

本当は上記のコマンドは

    % createdb ucms_app_development　-0 ucms_app
    % createdb ucms_app_test -0 ucms_app

として、オーナーを`username:`と同様の`ucms_app`でDB作成すれば良かったが、
どこかの段階でオーナーが切り替えられたのでよしとする。

     ucms_app_development=# ALTER ROLE "ucms_app" WITH Superuser;
     ALTER ROLE
多分ここ。

rails sすると下記になるのでmigrateを実行する

		ActiveRecord::PendingMigrationError (
		
		Migrations are pending. To resolve this issue, run:
		
				rails db:migrate RAILS_ENV=development
		
		):

####これでPostgreSQLのDB環境設定は完了！

##gem 'yaml_db'でsqlite3のデータをpgに移行

	gem 'yaml_db'
<!---->
	bundle exec rails db:data:dump
下記ファイルが作られる。

```db/data.yml
	   ーーー ar_internal_metadata:
			columns:
			- key
			- value
			- created_at
			- updated_at
			records: 
			- - environment
				- development
				- '2020-11-13 12:22:09.119176'
				- '2020-11-13 12:22:09.119176'
			
			---
			posts:
			columns:
			- id
			- title
			- content
			- start_time
			- user_id
			- created_at
			- updated_at
			records: 

			<!-- some long code -->

			- - 75
				- ddd
				- ddd
				- '2020-12-18 00:00:00'
				- 1
				- '2020-12-18 12:29:39.573445'
				- '2020-12-18 12:29:39.573445'
			
			<!-- some long code -->


			---
			users:
			columns:
			- id
			- name
			- email
			- seriousness
			- created_at
			- updated_at
			- password_digest
			records: 
			- - 1
				- sssss
				- s@gmail.com
				- 中等症
				- '2020-11-13 12:23:49.247847'
				- '2020-11-29 01:57:03.602324'
				- "$2a$12$/r0ip..."
				
			<!-- some long code -->

```

    % bundle exec rails db:data:load
PostgreSQLにこれで移行できる。

    ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR:  column "user_id" of relation "posts" does not exist
		LINE 1: ...INTO "posts" ("id","title","content","start_time","user_id",...
																	^
		bin/rails:4:in `<main>'
		
		Caused by:
		PG::UndefinedColumn: ERROR:  column "user_id" of relation "posts" does not exist
		LINE 1: ...INTO "posts" ("id","title","content","start_time","user_id",...
		
なぜか、postsのuser_idがなくなっている。。。
schema.rbが書き変わってる。。。なぜだ。。。

PostgreSQL導入前

    ActiveRecord::Schema.define(version: 2020_11_15_015429) do

		create_table "posts", force: :cascade do |t|
			t.string "title"
			t.text "content"
			t.datetime "start_time"
			t.integer "user_id"
			t.datetime "created_at", precision: 6, null: false
			t.datetime "updated_at", precision: 6, null: false
			t.index ["user_id", "created_at"], name: "index_posts_on_user_id_and_created_at"
			t.index ["user_id"], name: "index_posts_on_user_id"
		end

PostgreSQL導入後
		
		ActiveRecord::Schema.define(version: 2020_11_15_015429) do

		# These are extensions that must be enabled in order to support this database
		enable_extension "plpgsql"
		
		create_table "posts", force: :cascade do |t|
			t.string "title"
			t.text "content"
			t.datetime "start_time"
			t.datetime "created_at", precision: 6, null: false
			t.datetime "updated_at", precision: 6, null: false
		end

##直接、PostgreSQLに:user_id columnを作る！
		ucms_app_development=# ALTER TABLE posts ADD COLUMN user_id integer;  
   
		ALTER TABLE


		ucms_app_development=# \d posts

	                 Table "public.posts"
		Column   |              Type              | Collation | Nullable |              Default              
		------------+--------------------------------+-----------+----------+-----------------------------------
		id         | bigint                         |           | not null | nextval('posts_id_seq'::regclass)
		title      | character varying              |           |          | 
		content    | text                           |           |          | 
		start_time | timestamp without time zone    |           |          | 
		created_at | timestamp(6) without time zone |           | not null | 
		updated_at | timestamp(6) without time zone |           | not null | 
		user_id    | integer                        |           |          | 
		Indexes:
			"posts_pkey" PRIMARY KEY, btree (id)
		
		(END)

これでpostsテーブルにuser_id追加完了！
	
		% rails db:migrate              
		== 20201115015429 AddUserIdToPosts: migrating =================================
		== 20201115015429 AddUserIdToPosts: migrated (0.0000s) ========================
	
再度、% bundle exec rails db:data:loadでdb/data.ymlファイルをpgのDBに！

##本番環境herokuにDB適応させる！

     % heroku pg:psql           
		--> Connecting to postgresql...
		psql (13.1, server 12.5 (Ubuntu 12.5-1.pgdg16.04+1))
		SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
		Type "help" for help.


		ucmsapp...::DATABASE=> \d posts
												Table "public.posts"
		Column   |              Type              | Collation | Nullable |              Default              
		------------+--------------------------------+-----------+----------+-----------------------------------
		id         | bigint                         |           | not null | nextval('posts_id_seq'::regclass)
		title      | character varying              |           |          | 
		content    | text                           |           |          | 
		start_time | timestamp without time zone    |           |          | 
		created_at | timestamp(6) without time zone |           | not null | 
		updated_at | timestamp(6) without time zone |           | not null | 
		Indexes:
			"posts_pkey" PRIMARY KEY, btree (id)
		
		ucmsapp...::DATABASE=> ALTER TABLE posts ADD COLUMN user_id integer;
		ALTER TABLE

開発環境と同様にuser_idを作成

    % heroku run bundle exec rails db:data:load

~~もしかすると
% heroku run rails db:migrate
すれば良かっただけかも。~~
####ページ下部に追記あり。

##herokuに開発環境のDBをコピーするには？

		heroku pg:push ucms_app_development ucmsapp...             
		▸    Unknown database: ucmsapp... Valid options are:
		▸    DATABASE_URL

```config/database.yml

	#You can use this database configuration with:
	#
	#   production:
	#     url: <%= ENV['DATABASE_URL'] %>
```

 productionのurlは'DATABASE_URL'とのこと。

		heroku pg:push ucms_app_development DATABASE_URL
		heroku-cli: Pushing ucms_app_development ---> postgresql...
		▸    Remote database is not empty. Please create a new database or use
		▸    heroku pg:reset
		
		heroku pg:reset                    
		▸    WARNING: Destructive action
		▸    postgresql... will lose all of its data
		▸    
		▸    To proceed, type ucmsapp... or re-run
		▸    this command with --confirm ucmsapp...
		
		> ucmsapp...
		Resetting postgresql... done
<!---->
		heroku pg:push ucms_app_development DATABASE_URL               
		heroku-cli: Pushing ucms_app_development ---> postgresql...
		pg_dump: last built-in OID is 16383
		pg_dump: reading extensions
		pg_dump: identifying extension members

			<!-- some long code -->

		pg_restore: creating CONSTRAINT "public.posts posts_pkey"
		pg_restore: creating CONSTRAINT "public.schema_migrations schema_migrations_pkey"
		pg_restore: creating CONSTRAINT "public.users users_pkey"
		heroku-cli: Pushing complete.

<!---->

##まとめ
本番環境DBがPostgreSQLで、DBを移行することができた！
何故、postsテーブルにuser_id columnだけが存在しなくなるのかはわからなかったので、
その疑問もいつか解決できれば！


##追記　２０２１.０１.３１
ポートフォリオ作成を進める中で、開発環境でDBをいじり、本番環境herokuで下記を実行した。

    % heroku run rails db:migrate
    
    AddRememberDigestToUsers (20210125071004)
    == 20210125071004 AddRememberDigestToUsers: migrating =========================
    -- add_column(:users, :remember_digest, :string)
    D, [2021-01-31T01:12:39.614474 #4] DEBUG -- :    (0.7ms)  BEGIN
    D, [2021-01-31T01:12:39.622072 #4] DEBUG -- :    (7.4ms)  ALTER TABLE "users" 
    ADD "remember_digest" character varying
    -> 0.0089s
    == 20210125071004 AddRememberDigestToUsers: migrated (0.0090s) ================
      
DBの変更はできている。が、
####本番環境ではDBの変更を伴う機能が動作しなかったため、DB上のデータ自体は反映されないことがわかった！

そこで上記と同様に、

    heroku pg:push ucms_app_development DATABASE_URL 
	<!-- some long code -->
    heroku pg:reset 
	<!-- some long code -->
    heroku pg:push ucms_app_development DATABASE_URL 

で、本番環境herokuに開発環境のデータを反映でき、上手く機能を実行できた！

###結論として、pgでは、DBの変更とデータの反映は別々に行なう！