読者です 読者をやめる 読者になる 読者になる

LGTM

Looks Good To Me

heroku のassets:precompile 時に環境変数を有効にする

アプリケーションを heroku に push したとき, ローカル側でassets:precompileしていなければ heroku 側で実行してくれます.

そのときheroku config:addした環境変数をセットしてくれないようですが, それだと困る場合があります.

そんなときは

$ heroku labs:enable user-env-compile

しておくとよい, という話です.

困ったケース: Devise

認証に Devise を使うことがあるのですが, 3.1.0 からconfig.secret_keyが必要になりました.

Store digested tokens in the database

In previous versions, Devise stored the tokens for confirmation, reset password and unlock directly in the database. This meant that somebody with read access to the database could use such tokens to sign in as someone else by, for example, resetting their password.

In Devise 3.1, we store an encrypted token in the database and the actual token is sent only via e-mail to the user. This means that:

  • Devise now requires a config.secret_key configuration. As soon as you boot your application under Devise 3.1, you will get an error with information about how to proceed;

Devise 3.1: Now with more secure defaults

具体的には下のように書くことになります.

# config/initializers/devise.rb

Devise.setup do |config|
  config.secret_key = 'ebc54c9828a33e09f76b64aa6d9e38388fe889d7ded1230fcc83d6f20c9b658017e7deb77f89a566d5caa71178a4b3edc02c5437f54df9ec3af5090e4e517930'  # dummy
end

ですが, secret key を git 管理下に置きたくないため

$ heroku config:add DEVISE_SECRET_KEY=ebc54c9828a33e09f76b64aa6d9e38388fe889d7ded1230fcc83d6f20c9b658017e7deb77f89a566d5caa71178a4b3edc02c5437f54df9ec3af5090e4e517930

しておいて

# config/initializers/devise.rb

Devise.setup do |config|
  config.secret_key = ENV['DEVISE_SECRET_KEY']
end

とやりたいところ.

haroku だと動かない

$ git push heroku master

...

-----> Preparing app for Rails asset pipeline
       Running: rake assets:precompile
       rake aborted!
       Devise.secret_key was not set. Please add the following to your Devise initializer:
       config.secret_key = '3b87f9fcbf475d3bd3c197f47a4fc62d7a162bfd8a564420468ca944c1585d88521f5bf85a20cd38fa50845a6c

失敗. どうやら config vars が効いていない気がします.

heroku のAsset Pipeline

Compiling assets during slug compilation

The app's config vars are not available in the environment during the slug compilation process. Because the app must be loaded to run the assets:precompile task, any initialization code that requires existence of config vars should gracefully handle the nil case.

If you have not compiled assets locally, we will attempt to run the assets:precompile task during slug compilation. Your push output will show:

Rails Asset Pipeline on Heroku Cedar

assets:precompile時は環境変数(app's config vars) が使えないようですね.

そこで下記のようにして 環境変数が使えるようにします.

$ heroku labs:enable user-env-compile -a myapp
-----> Enabling user-env-compile for myapp... done
WARNING: This feature is experimental and may change or be removed without notice.

This Heroku Labs feature adds experimental support for having an app's config vars be present in the environment during slug compilation.

Features added through Heroku Labs are experimental and subject to change.

Using this labs feature is considered counter to Heroku best practices. This labs feature can make your builds less deterministic and require re-deploys after making config changes. Ideally your app should be able to build without config.

Heroku Labs: user-env-compile

再度 push してみると, 今度はassets:precompileできるようになりました.

$ git push heroku master

...

-----> Preparing app for Rails asset pipeline
       Running: rake assets:precompile

...

       Asset precompilation completed (17.57s)
       Cleaning assets
       Running: rake assets:clean

注意: あまり良い方法ではない

この機能が Heroku "Labs" なのは, Heroku のベストプラクティスから離れてしまうからです.

一般的には

config が変わるたびに build (assets:precompileなど) を実行するのはおかしいので

  • build したものは config を変更しても動く
  • build するのに, config を要求しない

というつくりを目指すべきです.

devise という gem がその条件を満たしていないかもしれませんね... またあとで調べてみよう.

補足

heroku config:addするときは dotenv を併用するとべんりです.