普通にRails扱うのと、Herokuにあげる用のRailsを扱うのとではやはり構造とかを多少変える必要がある。
以下のやり方は、厳密に言えば「できる限り本番と同じ環境にした方が良い」というやり方とは違うため、この方法をするのであれば、必ずHerokuにstaging環境のアプリをもう一つ作ることを推奨する。やり方は以下を参照していただきたい。
さて、今回はローカルとHerokuで共に開発しやすい環境を作るTIPSをお届けする。
Gemfile 構成
以下が基本的なテンプレートとなる。
group :production, :staging do gem 'pg' gem 'rails_12factor' end group :test, :development do gem 'sqlite3' gem 'dotenv-rails', '0.11.1' end gem 'asset_sync' gem 'unicorn' gem 'redis' gem 'redis-rails'
pg と sqlite3 の使い分け
まず注意したいのが、HerokuはPostgresqlを利用するということで、production と staging 環境では pg をインストールするようにする。 反対に development と test ではsqlite3 を利用する。
ローカル環境で bundle install
するときは、--without オプションをつけるようにする。
bundle install --without production staging
こうすることでローカルマシンに postgresql が入っていなくとも bundle install
が成功する。
herokuにソースをデプロイする際は git push heroku master
とかやれば勝手に 各環境だけの bundle install をしてくれるので心配はない。
やはりpostgresql と sqlite3 というDBの違いで問題が出てくることがある。 特に ActiveRecordを使わずに生のSQLを発行していたりすると問題が発生する確率が高まる。そんなときは心苦しいけども、
if Rails.env.development? || Rails.env.test? .. else .. end
と書けばOK。
そもそもなんで分けるのかというと、postgresql の環境構築が手間だからというだけなので、 本当なら ローカルに Postgresql を入れた方が良い。
まぁそんなこと気にせず vagrant とか使えばいいのだけども、わざわざ vagrant 起動して ssh とかで入って開発というのも面倒なので、という色々と楽をしたいがゆえのこの構成である。
環境変数の扱い
環境ごとの値の差分 (例えば外部サービスの Auth トークンなど) はそれぞれ分けたいところだろう。そこをローカル環境で便利に扱えるのが dotenv-rails
だ。これはherokuを使うなら必須と言ってもいいgemである。
Railsプロジェクト直下に .env
を配置し、
AWS_TOKEN: ....... AWS_SECRET: .......
などのように環境変数を定義し、ソースの中で ENV['AWS_TOKEN']
と書けばその設定を読み込むことができる。
Herokuの環境に環境変数を反映したい場合は、 heroku config
を利用する。 heroku config:set AWS_TOKEN=....
とすればセット完了だ。
セッションストアとしての Redis と Cookie
ローカルでわざわざ Redis を立ち上げるのが面倒な場合、ローカルでは Cookie, Herokuでは Redisと切り替えることができる。これには config/initializers/session_store.rb
にて
if Rails.env.development? || Rails.env.test? Rails.application.config.session_store :cookie_store, key: '_myapp_session' else Rails.application.config.session_store :redis_store, servers: ENV['REDIS_URL'], expire_in: 1.day end
とすれば良い。これでローカルでもRedisを起動せずともエラーが出ずに開発が可能だ。
Unicorn の設定
これは Heroku のときに Unicornなどのアプリケーションサーバを使のは必須。デフォルトではWebrick を使っているのでパフォーマンスが明らかに違う。 Heroku x Rails にするなら必ずやっておきたい設定だ。
config/unicorn.rb
に以下をコピペしよう。詳細はDeploying Rails Applications with Unicorn | Heroku Dev Centerを参照していただきたい。
# config/unicorn.rb worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3) timeout 20 preload_app true before_fork do |server, worker| Signal.trap 'TERM' do puts 'Unicorn master intercepting TERM and sending myself QUIT instead' Process.kill 'QUIT', Process.pid end defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! end after_fork do |server, worker| Signal.trap 'TERM' do puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT' end defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection end
ローカルで開発するぶんには、 rails server
で普通に立ち上げれば良い。
Asset Sync
更新
Asset Syncを利用するのは公式で止めるよう勧告が出ている。CloudFrontを利用する方法が推奨されている。以下の内容は古いのでご注意を。
Heroku に画像やCSSなどを全て読み込ませるには効率が悪い。これらは Amazon S3などから読み込めるようにしよう。具体的な方法はAssetSync/asset_sync · GitHubにある。
config/asset_sync.yml
にて
defaults: &defaults fog_provider: 'AWS' aws_access_key_id: "<%= ENV['AWS_ACCESS_KEY_ID'] %>" aws_secret_access_key: "<%= ENV['AWS_SECRET_ACCESS_KEY'] %>" fog_directory: "<%= ENV['AWS_S3_BUCKET'] %>" fog_region: "<%= ENV['AWS_REGION'] %>" existing_remote_files: delete gzip_compression: true fail_silently: true development: <<: *defaults enabled: false test: <<: *defaults enabled: false staging: <<: *defaults production: <<: *defaults
こんな感じでセットしてあげればOK。 ENV
が各 heroku config から値を読み込んでくれる。