学習メモ用です。
#解決したい問題
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も同様に置き換わる)
<!-- 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
の詳しい中身はこちら。
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
下記ファイルが作られる。
ーーー 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
#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だけが存在しなくなるのかはわからなかったので、
その疑問もいつか解決できれば!
##追記 2021.01.31
ポートフォリオ作成を進める中で、開発環境で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の変更とデータの反映は別々に行なう!