成らぬは人の為さぬなりけり

エンジニアライフをエンジョイする為のブログ

Heroku+Rails4+Devise+MySQL+Redis

今日いろいろやってみて、はまったポイント等をメモ。

環境

  • MacOSX 10.8.3
  • Ruby 2.0.0p0 (アップデートしなきゃ、、、)
  • Rails 4.0.0

今回の流れ

  1. toolbeltをインストール
  2. herokuのローカルセットアップ
  3. MySQLを使う設定
  4. Redisを使う設定
  5. Railsアプリのproduction設定をいろいろいじる
  6. デプロイしてみる
  7. ハマったポイント

Toolbelt

以前はherokuのgemでいろいろやる感じでしたが、
現在はgemは非推奨になり、
toolbeltが公式に推奨されているようです。

herokuコマンドをgemでインストールしたものからheroku toolbeltのものに置き換える - Qiita [キータ]

こちらを参考にgemをアンインストールして、toolbeltをインストールします。

$ heroku version
heroku-toolbelt/2.40.0 (x86_64-darwin10.8.0) ruby/1.9.3

rubyが1.9.3になってるけど、とりあえず動くので、まぁ後で考える事にします。

herokuのローカルセットアップ

herokuコマンドのインストールが終わったので、
いろいろセットアップします。

基本的には公式ドキュメントに沿ってやれば問題ありません。(な気がします)
Getting Started with Rails 4.x on Heroku | Heroku Dev Center

※以下、既にRailsアプリがある事前提です。

herokuにログインする

$ heroku login
Enter your Heroku credentials.
Email: hoge@gmail.com
Password (typing will be hidden): 
Authentication successful.
  • Email : herokuアカウントのEmailを入力
  • Password : herokuアカウントのパスワードを入力

一応、公開鍵を登録しとく

heroku keys:addしなくても大丈夫っぽい???
一応、やっときます。

$ heroku keys:add
Found existing public key: /Users/hoge/.ssh/id_rsa.pub
Uploading SSH public key /Users/hoge/.ssh/id_rsa.pub... done

herokuにアプリを登録する

$ heroku create sample-app

この時点で、herokuというリモートリポジトリが登録されます。

MySQLを使う設定

HerokuのデフォルトDBはPostgreSQLなので、MySQLを使えるようにします。

ClearDB MySQL Database | Heroku Dev Center

Addonを追加

$ heroku addons:add cleardb:ignite 

環境変数の設定

HerokuはRailsアプリをデプロイする時に環境変数から
config/databse.ymlを自動で作ってくれるので
環境変数を更新しておきます。

まずは、MySQLのURLを見る

$ heroku config | grep CLEARDB_DATABASE_URL
CLEARDB_DATABASE_URL:       mysql://<username>:<password>@<host>/<databse>?reconnect=true

いろいろ伏せましたが、そこはどうでも良いので、大丈夫。
mysql://...
の部分をコピっておきます。
今回はドライバをmysql2にしたいので、
上記のmysqlの部分をmysql2にして、以下の様に実行。

$ heroku config:set DATABASE_URL='mysql2://<username>:<password>@<host>/<database>?reconnect=true'

これでHerokuでMySQLが使えるようになった、はず!

Redisを使う設定

今回は、手軽にRedisToGoを使います。

$ heroku addons:add redistogo

以上、OK。

Railsアプリのproduction設定をいろいろいじる

まずは、Gemfile

今回は

を使いたいので、Gemfileを修正。

ruby "2.0.0", group: [:production]
gem 'mysql2', group: [:production, :development]

※ 普通に group :production doでも良いと思います。

今回は、

  • ローカルはRVM使ってるので、 ruby の指定はproductionだけにする
  • 開発環境もMySQLなので、mysql2のgroupにdevelopmentも入れとく

にしてます。

Deviseの設定

DeviseでTwitterFacebookGoogleなどの認証を使っている場合、
keyとsecretをコードにベタ書きしたくないです。
なので、環境変数から取ってくるようにします。

herokuの環境変数設定

先程、MySQLの設定で使った
heroku config:set
環境変数を設定できます。

heroku config:set TWITTER_KEY="xxxx"
heroku config:set TWITTER_SECRET="xxxx"
設定されている環境変数を確認する
$ heroku config
=== sample-app Config Vars
CLEARDB_DATABASE_URL:       mysql://...
DATABASE_URL:               mysql2://...
HEROKU_POSTGRESQL_GOLD_URL: postgres://...
REDISTOGO_URL:              redis://redistogo:...
TWITTER_KEY:                xxxx
TWITTER_SECRET:             xxxx
config/initializers/devise.rbを編集

今回は、deviseの設定をenvironmentsの方でやってないので、
config/initializers/devise.rb
を編集します。

  unless Rails.env.production?
    # test development の設定
  else
    Devise.setup do |config|
      config.omniauth :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET'], :display => 'popup'
    end
  end

RedisStoreの設定

今回はsession_storeにredis-storeを使っているので、
config/initializers/session_store.rbを編集します。

if Rails.env.production? and ENV['REDISTOGO_URL']
  redis_uri = URI(ENV['REDISTOGO_URL'])
  Sepia::Application.config.session_store :redis_store, :servers => {
    host: redis_uri.host,
    port: redis_uri.port,
    password: redis_uri.password,
    namespace: "sample-app:sessions"
  }, expire_in: 120.minutes
else
  # test development の設定
end

デプロイしてみる

※今までの変更はcommit済みとします。

デプロイはgitでpushするだけです。

$ git push heroku heroku:master

ローカルのherokuブランチをherokuのmasterブランチにpushしました。

Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 348 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)

-----> Ruby/Rails app detected
-----> Using Ruby version: ruby-2.0.0
-----> Installing dependencies using Bundler version 1.3.2
       Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin --deployment
       Using rake (10.1.0)
       ... (省略)
       Your bundle is complete! It was installed into ./vendor/bundle
       Cleaning up the bundler cache.
-----> Writing config/database.yml to read from DATABASE_URL
-----> Preparing app for Rails asset pipeline
       Running: rake assets:precompile
       Asset precompilation completed (19.08s)
       Cleaning assets
-----> WARNINGS:
       Include "rails_12factor" gem to enable all platform features
       See https://devcenter.heroku.com/articles/rails-integration-gems for more information.
-----> Discovering process types
       Procfile declares types      -> (none)
       Default types for Ruby/Rails -> console, rake, web, worker

-----> Compiled slug size: 61.1MB
-----> Launching... done, v33
       http://sample-app.herokuapp.com deployed to Heroku

To git@heroku.com:sample-app.git
   2e4707c..54e8fb1  heroku -> master

assets:precompileまでやってくれてますね、こいつが結構曲者なんですが、、、

というわけで、デプロイまで完了。

ハマったポイント

assets:precompile時に環境変数が取得できない

そうなんです、デプロイされる時のassets:precompile時点だと
環境変数がセットされてないのです。

Heroku に Rails 3.1 アプリを git push すると rake assets:precompile でエラーが出るときの対処法 - babie cruising love

config.assets.initialize_on_precompileオプションで
precompileさせなくできるのかなぁ、と思ったんですが、出来ない。

Getting Started with Rails 4.x on Heroku | Heroku Dev Center

assetsのコンパイルが失敗するとpushが失敗する、と。うーむ。なるほど。
まぁ、確かに正しいんだけど、、、

環境変数が起動時になければエラーにしたいと思っていたんですが、
precompileの時に無いとエラーになってしまう。。。

ではどうするか。

環境変数がある時だけ実行するようにする

今回はこれで逃げました。
エラーにしたかったなぁ。。。

環境変数を見れるようにする

Heroku Labs: user-env-compile | Heroku Dev Center

こいつを使えばassets:precompile時にも環境変数が見れるっぽい

試しに、やってみます。

$ heroku labs:enable user-env-compile -a sample-app

redisのinitializerで環境変数がない時にエラーになるようにしてみます。
config/intializers/session_store.rb

if Rails.env.production?
  raise "no env RedisToGo" unless ENV['REDISTOGO_URL']
  redis_uri = URI(ENV['REDISTOGO_URL'])
  Sepia::Application.config.session_store :redis_store, :servers => {
    host: redis_uri.host,
    port: redis_uri.port,
    password: redis_uri.password,
    namespace: "sepia:sessions"
  }, expire_in: 120.minutes
else
... (省略)

デプロイしたら、問題なくデプロイされました。

...(省略)
-----> Preparing app for Rails asset pipeline
       Running: rake assets:precompile
       Asset precompilation completed (18.66s)
       Cleaning assets
...(省略)

ついでに、この設定をオフって

$ heroku labs:disable user-env-compile -a sample-app

で試してみると、ちゃんと(?)raiseされました。

ただ、

Heroku Labs: user-env-compile | Heroku Dev Center

にもある通り、注意が必要。

その他

静的ファイル

Herokuの設定とは関係ないですが、public配下の静的ファイルをRails通して返す場合は、
config/environments/production.rb

  config.serve_static_assets = true

が必要。

assetsの設定忘れずに

development環境だと、分割されて読み込まれるので、あまり意識しませんが、

のapplication.jsとかapplication.cssとかで読み込んでないファイルがある時は、

config/environments/production.rb

  config.assets.precompile += %w( hoge.js hoge.css )

が必要。

当たり前なんですが、忘れてたので、、、

まとめ

  • 環境変数が簡単につかえて便利
  • 便利なんですが、自由が効かない所もありますね。と。
  • 今回Sidekiqも使いたかったんですが、RescueとかSidekiqのワーカーを起動すると、お金かかるっぽい?ので、今回は諦めました。