Pow + Rails + Devise 環境で undefined method エラー → 解決

Powの上でDeviseを使ったRailsアプリケーションを動かそうとしたところ、以下のようなエラーが発生し、盛大にハマってしまったのでメモ。

長いので、結論だけ読みたい方は最後の「まとめ」に飛んでくださいね。

問題詳細

PowはMac OS X用のRackサーバ。ほぼ設定することなく、複数のRackアプリケーションを動作させられるのが特徴。

この度、Railsアプリの開発環境をシンプルにしたいという意図で、UnicornからPowへの移行作業を行なっていたのですが、user_omniauth_authorize_pathというヘルパーメソッドを含んだビューにアクセスしたタイミングで、上記エラーが発生するようになってしまいました。

user_omniauth_authorize_pathメソッドは、DeviseというRails用認証用プラグインが生成するヘルパーメソッド。

Powに移行する前はエラーが発生していなかったので、移行作業に何らかの原因があることまではわかりました。

ちなみに、問題発生時の環境は以下のとおり。

  • Pow – 0.4.0
  • Rails – 3.2.1
  • Devise – 2.0.4

トラブルシューティングその1

気をとりなおして、まずはrails sコマンドでRailsアプリを起動し、問題のビューにアクセス。すると、エラーが発生することなくページが表示されました。

rails sコマンドでRailsアプリを起動するのと、Powを使って起動するのとで何が違うんだろう」と不思議に思ったので、PowがどうやってRailsアプリを起動しているのかを調べました。

どうやらPowは、rackupファイルと呼ばれるconfig.ruを読み込むことでアプリを起動している模様。

試しにrackupコマンドでRailsアプリを起動し、問題のビューにアクセス。するとPowで起動した場合と同様にエラーが発生することを確認しました。

この時点で、

  • rackupコマンドを使った場合と、rails sコマンドを使った場合で、Railsの動作環境に微妙な違いが生じる
  • その違いが原因でDeviseがヘルパーメソッドを生成してくれる場合とそうでない場合がある。

のように推測することができました。

トラブルシューティングその2

その後はしばらくの間悩みまくり。

最終的に、Railsアプリ起動時の環境変数に違いがあるのではないかと疑い始めました。

rails sコマンドは、アプリ起動時に何らかの環境変数を追加していて、rackupコマンドではそれがないからDeviseがヘルパーメソッドを生成しないんじゃないかと。

起動中のRailsアプリに紐付いた環境変数をかんたんに調べる方法がわからなかったので、今流行のPryを使って簡易デバッグしてみることにしました。

Railsアプリの適当なところに、以下の行を挿入。

コードの実行が上記の行に到達すると、実行が一旦停止しPryのコンソールが立ち上がります。

rails srackupそれぞれでの実行時に、環境変数が格納されている変数ENVの中身をPryを使って表示させ、両者を比較する作業を行いました。

その結果・・・。

rackupコマンドよるRailsアプリ起動時には、環境変数RAILS_ENVが定義されていないことがわかりました。光が見えてきた!

最後の仕上げ

PowでのRailsアプリ実行時に環境変数RAILS_ENVを定義できれば、エラーは発生しなくなる。そう信じこんで、そのための方法を調べました。

方法はいたって簡単。

Railsアプリのルートディレクトリに.powrcというファイルを作って、以下の内容を記述するだけです。

上記ファイルを作成後、Powを再起動し、問題のビューにアクセスしたところ、無事エラーが発生すること無くページがひょうじされることを確認しました。

長かった。

まとめ

Powは、アプリケーションをあくまでもRackアプリとして起動します。

Railsアプリとしてではないので、環境変数RAILS_ENVは定義されない。(RACK_ENVは定義される。)

DeviseはおそらくRAILS_ENVの有無をみてヘルパーメソッドを生成するかどうか判断しているみたい。

PowにアプリケーションをRailsアプリとして起動して欲しい場合は、.powrcRAILS_ENVを定義する一行を書いてあげればOK。

他にもいい方法があるかもしれませんが、ひとまず解決できてよかったです。Devise以外にもRAILS_ENVを参照しているgemがあるかもしれないので、今後PowでRailsアプリを動かすときは気をつけようと思いました。

こんな長文・駄文ですが、どこかで困っている誰かのお役に立てれば幸いです。
それでは。