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


はじめに

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

開発環境

  • Rails 5.2.3
  • Ruby 2.6.2
  • Bundler 2.0.1

ユーザー認証機能の実装 / Herokuへのデプロイ

以下のサイトを参考にしました。

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

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

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としてリポジトリの外で管理するキーとなります。

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

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

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

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

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を有効化することが推奨されています。

config/environments/production.rb
config.require_master_key = true

上記が有効の場合、master keyが指定されてない状態でサーバ起動を実行しようとするとエラーになります。
詳しくはこちらを参照して下さい。

$ 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環境の設定を見直してみて下さい。

config/environments/production.rb
config.assets.compile = true

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

config/environments/production.rb
config.force_ssl = true

以下を参考にしました。

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を入れる

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

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

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

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

以下を参考にしました。

Rails: deviseをインストールした後のエラー

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

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

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

以下を参考にしました。

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

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

以下を参考にしました。

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の内容を手動で削除する

エラーメッセージの通りに実行するのではなく、以下のようにしてください。

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

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

ターミナル
$ bundle config --delete frozen

以下を参考にしました。

BUNDLED WITH で Gemfile.lock が更新されてしまう件

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

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

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

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

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

その他参考になったサイト

補足

もしよろしければこちらも参考にしていただけるとありがたいです。
余談ですが、Rails 5.xからHerokuのログ出力等をサポートするGem、rails_12factorが要らなくなりました。