Rails5.2.3 / Devise / OmniAuthを使って開発&Herokuへデプロイした際にハマったこと&気をつけること

# はじめに
静的サイトにユーザー認証機能(Twitter/FacebookのSNSアカウントでもログイン可)を実装し本番環境へデプロイしたら色々ハマったのでここに書き留めておきたいと思います。
約4日間苦戦しました。
同じような境遇の方がいらっしゃいましたら参考にしていただけるとありがたいです。


# 開発環境
- Rails 5.2.3
- Ruby 2.6.2
- Bundler 2.0.1


# ユーザー認証機能の実装 / Herokuへのデプロイ
以下のサイトを参考にしました。

- [[Rails] Facebook/Twitter/Googleでのユーザー登録をDevise & Omniauthを使って爆速で実装する](https://qiita.com/kazuooooo/items/47e7d426cbb33355590e)
- [【初心者向け】railsアプリをherokuを使って確実にデプロイする方法【決定版】](https://qiita.com/kazukimatsumoto/items/a0daa7281a3948701c39)


# 1. devise.rbの設定でハマった

初心者にありがちですが以下のままでは動作しません。
また、API情報をコードへ直に埋め込むのもセキュリティ上非常に危険です。
コールバックURLもAPI側のURLと一致するようにしましょう。ここを間違えるとエラーが出ます。

```ruby:config/initializers/devise.rb
Devise.setup do |config|
# --省略--
  config.omniauth :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET'], scope: 'email', info_fields: 'email', callback_url: "https://hogehoge.herokuapp.com/users/auth/facebook/callback"
  config.omniauth :twitter, ENV['TWITTER_API_KEY'], ENV['TWITTER_API_SECRET'], scope: 'email', oauth_callback: "https://hogehoge.herokuapp.com/auth/twitter/callback"
# --省略--
end
```

## Credentialsを使う(推奨)

Rails 5.1まではproduction環境用の秘密情報(Twitter API等)の管理を環境変数でアプリケーションに伝える方法が使われていましたが、Rails 5.2からCredentialsという新しい機能が追加されました。

Credentialsは秘密情報を構造化して記述しリポジトリで管理できるようにしますが、リポジトリに入る内容はある一つのキーで暗号化されます。そして、そのキーはリポジトリの外で管理し、アプリケーションが複合して利用できるようにします。
config/master.keyとしてリポジトリの外で管理するキーとなります。

以下を参考にさせて頂きました。

- [secrets.ymlや環境変数をRails 5.2のEncrypted Credentialsに移行する](https://qiita.com/d-mato/items/aab2b6b2f587a8582631#%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4)

- [herokuへデプロイできない](https://teratail.com/questions/163759)


```ruby:config/credentials.yml.enc
twitter:
  twitter_api_key: # ここにキーを入力
  twitter_api_secret: # ここにキーを入力

facebook:
  facebook_key: # ここにキーを入力
  facebook_secret: # ここにキーを入力
```

deviseへのAPI呼び出しは以下のように変更します。
コールバックURLは開発時は動作確認の為ローカルホストのURL等に設定しても構いません。
本番環境へデプロイする際は必ず本番環境でのコールバックURLに変更してください。

```ruby:config/initializers/devise.rb
Devise.setup do |config|
# --省略--
  config.omniauth :facebook, Rails.application.credentials.facebook[:facebook_key], Rails.application.credentials.facebook[:facebook_secret], scope: 'email', info_fields: 'email', callback_url: "https://hogehoge.herokuapp.com/users/auth/facebook/callback"
  config.omniauth :twitter, Rails.application.credentials.twitter[:twitter_api_key], Rails.application.credentials.twitter[:twitter_api_secret], scope: 'email', oauth_callback: "https://hogehoge.herokuapp.com/auth/twitter/callback"
# --省略--
end
```

本番環境ではmaster keyの指定漏れを防ぐためにconfig/environments/production.rbでconfig.require_master_key = trueを有効化することが推奨されています。

```ruby:config/environments/production.rb
config.require_master_key = true
```

上記が有効の場合、master keyが指定されてない状態でサーバ起動を実行しようとするとエラーになります。
詳しくは[こちら](https://qiita.com/NaokiIshimura/items/2a179f2ab910992c4d39)を参照して下さい。

```terminal
$ rails s

=> Booting Puma
=> Rails 5.2.0 application starting in development
=> Run `rails server -h` for more startup options
Missing encryption key to decrypt file with. Ask your team for your master key and write it to /xxx/my-app/config/master.key or put it in the ENV['RAILS_MASTER_KEY'].
Exiting
```


# 2. デプロイ時に Precompiling assets failed.が出て失敗する


>  !     Precompiling assets failed.
 !
 !     Push rejected, failed to compile Ruby app.
 !     Push failed


## config.assets.compile = falseになってないか確認

production環境の設定を見直してみて下さい。

```ruby:config/environments/production.rb
config.assets.compile = true
```

また、HTTPSでアクセスできるようにするには以下のように変更してください。(デフォルトではfalse)

```ruby:config/environments/production.rb
config.force_ssl = true
```

以下を参考にしました。

- [Herokuで画像が表示されなかった時の解決法](https://qiita.com/tsumichan/items/4daf7355eb6c4f947912)

- [Rails Asset Pipelineがうまくいかないときの問題の切り分けかた](https://qiita.com/metheglin/items/c5c756246b7afbd34ae2)

- [railsアプリをherokuにデプロイするとき割とつまづいたのでメモ](https://qiita.com/shinoharat/items/1a5b6023acf145ec53e6)



# 3. デプロイ時にHerokuのRuby/Node.jsビルドパックを入れろと言わる

yarnが入っていないと怒られました。

> !     Warning: Multiple default buildpacks reported the ability to handle this app. The first buildpack in the list below will be used.
			Detected buildpacks: Ruby,Node.js
			See https://devcenter.heroku.com/articles/buildpacks#buildpack-detect-order

## HerokuビルドパックRuby/Node.jsを入れる

```terminal:ターミナル
$ heroku buildpacks:add --index 1 heroku/nodejs
$ heroku buildpacks:add --index 2 heroku/ruby
```

以下を参考にして下さい。

- [【Rails】Production環境のために必要な設定](http://thoames.hatenadiary.jp/entry/2018/07/10/225204)
- [yarnを使ってみた](https://qiita.com/masterkey1009/items/50f95b1187646a7db385)
- [Heroku公式サイト](https://devcenter.heroku.com/articles/buildpacks#buildpack-detect-order)


# 4. デプロイ時にUserモデルに対してdeviseメソッドが見つからないと言われる

> NoMethodError: undefined method `devise' for User (call 'User.connection' to establish a connection):Class

以下を参考にしました。

[Rails: deviseをインストールした後のエラー](https://qiita.com/penguin_note/items/93b00c09c0da1f1a0eab)

# 5. 4.がそれでもまだ解決しない場合

Userモデルに以下を追加して下さい。
私はこれで解決しました。

```ruby:models/user.rb
class User < ApplicationRecord
  extend Devise::Models
# --省略--
end
```

以下を参考にしました。

- [undefined method `devise' with Rails 5 #3877](https://github.com/plataformatec/devise/issues/3877)
- [method_missing: undefined method `devise' for User (call 'User.connection' to establish a connection)](https://stackoverflow.com/questions/24196258/method-missing-undefined-method-devise-for-user-call-user-connection-to)


# 6. Twitterアカウントでログインしたらまたログイン画面に戻ってしまう(Facebookアカウントでログインした場合は成功)

私の場合何回かデプロイしてたら解消されてしまったので原因がわかりません。

以下を参考にしました。

- [Twitter連携のログイン機能を作る(【gem】twitter-omniauth)](https://blog.warally.info/entry/dev/twitter-omniauth)
- [OAuth::Unauthorized 401 Unauthorizedなんてエラーがでたら](https://qiita.com/hirokishirai/items/5a43977a38ecd922bfb9)

# 7. Bundleエラーが出る

> You are trying to install in deployment mode after changing
your Gemfile. Run `bundle install` elsewhere and add the
updated Gemfile.lock to version control.

> If this is a development machine, remove the Gemfile freeze
by running `bundle install --no-deployment`.


## .bundle/configの内容を手動で削除する
エラーメッセージの通りに実行するのではなく、以下のようにしてください。

```config:.bundle/config
---
BUNDLE_PATH: "vendor/bundle"
BUNDLE_FROZEN: '1'    ## この行を消す
```

コマンドからでも削除可能

```terminal:ターミナル
$ bundle config --delete frozen
```

以下を参考にしました。

[BUNDLED WITH で Gemfile.lock が更新されてしまう件](https://qiita.com/suu_g/items/2b1630b8015d51c5292e)


# 8. Heroku側がBundler 2.0に対応していない場合

私の場合は一度BundlerをダウングレードとHerokuのビルドパックBundler 2を入れて再度デプロイしたら、「Bundler 2は必要ないから削除してね」と言われてしまったのでアンインストールして再度デプロイしたら自然とBundler 2.0にアップグレードされてデプロイに成功しました。
謎です。(HerokuがBundler 2.0に対応したのかな？)

以下を参考にして下さい。

- [You must use Bundler 2 or greater with this lockfile.](https://qiita.com/yoshijbbsk1121/items/87250501b32c6433943e)
- [HerokuはまだBundler2.0に対応していない？](https://qiita.com/gonzaemon111/items/5aaffab894fa39b02a79)


# それでもデプロイが失敗する場合

HerokuはGemfile.lockの情報を元にbundleするのでGemfileとの整合性がとれていないとデプロイに失敗します。Gemfile.lockの内容を全て削除してbundle installをして再度デプロイしてみて下さい。

# その他参考になったサイト
- [本番環境のDBエラーに困っています（rails）](https://teratail.com/questions/77287)
- [herokuのデータベースをリセットした際の留意点](https://qiita.com/shiroux/items/b394c84a096fe48cfe83)
- [RailsでアプリをHerokuにあげる時のエラー各種](https://qiita.com/pokohide/items/017afa5be3b7dc200a8d)

# 補足

もしよろしければ[こちら](https://qiita.com/Hiro710/items/0e593ed18da431fc9f27)も参考にしていただけるとありがたいです。
余談ですが、Rails 5.xからHerokuのログ出力等をサポートするGem、rails_12factorが要らなくなりました。