Androidはワンツーパンチ 三歩進んで二歩下がる

Android卵プログラマーの記録ブログ

Herokuデプロイ後にdb:migrateが失敗した時の状況とやったこと

Rails勉強中です。Heroku使用経験もほとんどありません。
トラブル時に途中で混乱して手順を忘れてしまっている部分が多いのですが、
よい勉強になりましたので作業のメモを残しておきます。

全体のまとめ

Herokuにデプロイする前に
Gemfile.lockの中身を消してから
$ bundle install

変更をcommit

$ git push heroku master

$ heroku run rake db:migrate
すればよかったです。
Gemfile.lockを消してbundle install する箇所はbundle updateを実行することでもよいと思います。

前提

Rails5.0.1使用
作業時に使用していたOSはMac OS/X 10.11.6

状況

最新のソースをcommit → $ git push heroku master でデプロイ後、
データベースをmigrateするため、次のコマンドを叩いたらエラーが発生しました。

$ heroku run rake db:migrate

エラーメッセージは次のとおりです。今思えば全て取っておけば良かったのですが、最初の一部だけです。

Running rake db:migrate on ⬢ myapp... up, run.9784 (Free)
rake aborted!
Gem::LoadError: Specified 'postgresql' for database adapter, but the gem is not loaded. Add `gem 'pg'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord).

対策

公式サイトの導入ガイド
「Getting Started with Rails 5.x on Heroku」 に従ってちゃんと設定を出来ているか(特にdb関連)確認してみました。

Gemfileの確認

公式で「gem 'sqlite3' To this: gem 'pg'」とあるようにHerokuではPostgreSQLSaas形態で提供されているため、gemはpgを使用する必要があります。
ここで私はproduction環境向けに「gem 'pg'」を指定するのを忘れていましたので、指定しました。

Gemfile

 group :production do
  gem 'pg',             '0.15.1' 
  gem 'rails_12factor'
 end

database.ymlの確認

公式で、databaseのadapterはpostgresql を使うように等々ありましたので見直しました。
データベース名やらユーザー名やらは
$ heroku config
でも確認出来るのですが、Web上で見た方がわかりやすいと思います。
Herokuにログイン→アプリを選択→Add-onsにあるHerokuPostgresをクリック→Database CredentialsのView Credentialsボタンをクリックで参照出来ます。

config/database.yml

# SQLite version 3.x
#   gem install sqlite3
#
#   Ensure the SQLite 3 gem is defined in your Gemfile
#   gem 'sqlite3'
#
default: &default
  adapter: postgresql
  encoding: utf8
  # For details on connection pooling, see rails configuration guide
  # http://guides.rubyonrails.org/configuring.html#database-pooling
  pool: 5

# SQLite version 3.x
#   gem install sqlite3
development:
  adapter: sqlite3
  database: db/development.sqlite3
  pool: 5
  timeout: 5000

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  adapter: sqlite3
  database: db/test.sqlite3
  pool: 5
  timeout: 5000

#
production:
  <<: *default
  database: d8c7clp3dmvv4u
  username: ENV['DATABASE_USER']
  password: ENV['DATABASE_PASSWORD']
  host: ec2-23-23-222-147.compute-1.amazonaws.com
  port: 5432

変更をcommitして再度デプロイしましたがエラーが発生しました。
エラーメッセージは次のとおりです。

Running rake db:migrate on ⬢ myapp... up, run.9233 (Free)
rake aborted!
Gem::LoadError: Specified 'postgresql' for database adapter, but the gem is not loaded. Add `gem 'pg'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord).
/app/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/connection_specification.rb:176:in `rescue in spec'
/app/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/connection_specification.rb:173:in `spec'
/app/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_handling.rb:53:in `establish_connection'
/app/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/railtie.rb:125:in `block (2 levels) in <class:Railtie>'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/lazy_load_hooks.rb:38:in `instance_eval'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/lazy_load_hooks.rb:38:in `execute_hook'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/lazy_load_hooks.rb:28:in `block in on_load'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/lazy_load_hooks.rb:27:in `each'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/lazy_load_hooks.rb:27:in `on_load'
/app/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/railtie.rb:121:in `block in <class:Railtie>'
/app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0.1/lib/rails/initializable.rb:30:in `instance_exec'
/app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0.1/lib/rails/initializable.rb:30:in `run'
/app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0.1/lib/rails/initializable.rb:55:in `block in run_initializers'
/app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0.1/lib/rails/initializable.rb:54:in `run_initializers'
/app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0.1/lib/rails/application.rb:352:in `initialize!'
/app/config/environment.rb:5:in `<top (required)>'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:293:in `require'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:293:in `block in require'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:259:in `load_dependency'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:293:in `require'
/app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0.1/lib/rails/application.rb:328:in `require_environment!'
/app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0.1/lib/rails/application.rb:448:in `block in run_tasks_blocks'
/app/vendor/bundle/ruby/2.2.0/gems/rake-12.0.0/exe/rake:27:in `<top (required)>'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/cli/exec.rb:74:in `load'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/cli/exec.rb:74:in `kernel_load'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/cli/exec.rb:27:in `run'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/cli.rb:332:in `exec'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/vendor/thor/lib/thor/invocation.rb:126:in `invoke_command'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/vendor/thor/lib/thor.rb:359:in `dispatch'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/cli.rb:20:in `dispatch'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/vendor/thor/lib/thor/base.rb:440:in `start'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/cli.rb:11:in `start'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/exe/bundle:34:in `block in <top (required)>'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/friendly_errors.rb:100:in `with_friendly_errors'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/exe/bundle:26:in `<top (required)>'
/app/bin/bundle:3:in `load'
/app/bin/bundle:3:in `<main>'
Gem::LoadError: can't activate pg (~> 0.18), already activated pg-0.15.1. Make sure all dependencies are added to Gemfile.
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/rubygems_integration.rb:346:in `block (2 levels) in replace_gem'
/app/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/postgresql_adapter.rb:2:in `<top (required)>'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:293:in `require'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:293:in `block in require'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:259:in `load_dependency'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:293:in `require'
/app/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_adapters/connection_specification.rb:174:in `spec'
/app/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/connection_handling.rb:53:in `establish_connection'
/app/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/railtie.rb:125:in `block (2 levels) in <class:Railtie>'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/lazy_load_hooks.rb:38:in `instance_eval'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/lazy_load_hooks.rb:38:in `execute_hook'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/lazy_load_hooks.rb:28:in `block in on_load'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/lazy_load_hooks.rb:27:in `each'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/lazy_load_hooks.rb:27:in `on_load'
/app/vendor/bundle/ruby/2.2.0/gems/activerecord-5.0.0.1/lib/active_record/railtie.rb:121:in `block in <class:Railtie>'
/app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0.1/lib/rails/initializable.rb:30:in `instance_exec'
/app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0.1/lib/rails/initializable.rb:30:in `run'
/app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0.1/lib/rails/initializable.rb:55:in `block in run_initializers'
/app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0.1/lib/rails/initializable.rb:54:in `run_initializers'
/app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0.1/lib/rails/application.rb:352:in `initialize!'
/app/config/environment.rb:5:in `<top (required)>'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:293:in `require'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:293:in `block in require'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:259:in `load_dependency'
/app/vendor/bundle/ruby/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/dependencies.rb:293:in `require'
/app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0.1/lib/rails/application.rb:328:in `require_environment!'
/app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0.1/lib/rails/application.rb:448:in `block in run_tasks_blocks'
/app/vendor/bundle/ruby/2.2.0/gems/rake-12.0.0/exe/rake:27:in `<top (required)>'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/cli/exec.rb:74:in `load'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/cli/exec.rb:74:in `kernel_load'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/cli/exec.rb:27:in `run'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/cli.rb:332:in `exec'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/vendor/thor/lib/thor/invocation.rb:126:in `invoke_command'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/vendor/thor/lib/thor.rb:359:in `dispatch'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/cli.rb:20:in `dispatch'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/vendor/thor/lib/thor/base.rb:440:in `start'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/cli.rb:11:in `start'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/exe/bundle:34:in `block in <top (required)>'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/lib/bundler/friendly_errors.rb:100:in `with_friendly_errors'
/app/vendor/bundle/ruby/2.2.0/gems/bundler-1.13.7/exe/bundle:26:in `<top (required)>'
/app/bin/bundle:3:in `load'
/app/bin/bundle:3:in `<main>'
Tasks: TOP => db:migrate => environment
(See full trace by running task with --trace)

ここで色々調べまくってherokuのプロジェクトを一度消してからやり直したり、
Managing Gems with Bundler | Heroku Dev Centerにあるように開発環境のgemをインストールしないようにしたり、
dotenvを使って環境変数からユーザー名とパスワードを指定しているところを直接書いたりしてみましたが状況が変わることはありませんでした。

エラーメッセージの中に
「Gem::LoadError: can't activate pg (~> 0.18), already activated pg-0.15.1. Make sure all dependencies are added to Gemfile.」
とあるので関係があるかもしれないと思い

 gem 'pg',             '0.15.1'

としていたところを

 gem 'pg'

に変更して、production内に書いているだけではダメかもしれないと、デフォルトのところにも指定してみましたが状況は変わりませんでした。

そこで何となくGemfile.lockをのぞくと
pg (0.15.1)
となっていました。pgのバージョンを指定するのをやめたのに昔のものが残っているのか?と思い内容を全部消去してから

$ bundle install 

してから変更をcommitし、あらためてHerokuにデプロイし

$ heroku run rake db:migrate

しますと出来ました!

Running rake db:migrate on ⬢ myapp... up, run.5276 (Free)
   (54.7ms)  CREATE TABLE "schema_migrations" ("version" character varying PRIMARY KEY)
   (10.7ms)  CREATE TABLE "ar_internal_metadata" ("key" character varying PRIMARY KEY, "value" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
   (1.7ms)  SELECT pg_try_advisory_lock(4611527472350007090);
  ActiveRecord::SchemaMigration Load (1.3ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Migrating to CreateTypes (20170228141646)
   (1.1ms)  BEGIN
== 20170228141646 CreateTypes: migrating ======================================
-- create_table(:types)
(中略)

試してませんが、Gemfile.lockを消してbundle install する箇所はbundle updateを実行することでもよいと思います。

まとめ

  • pg (0.15.1)のままであったとしても何故エラーになるのかがはっきりとはわかりませんでしたが、現時点(2017/03/28)でサーバー側のPostgresSQLは0.19.0が最新のようなので明らかに古いので問題があっとということだと解釈しました。
  • 違う環境にデプロイする時はGemfile.lockに注意する必要があることを学習しました。
  • 今回の件には関係ありませんが、push時にHeroku側で毎回bundle installしているみたいなのですが、これは省略出来ないのだろうか、できたらいいのにと感じました。やり方はあるのかもしれないのですが、発見できませんでした。