technologiesHomeArticlesaboutTechUnicornのホットデプロイについて会社の方に書きました去年の9月からKRAYで働いているのですが、そちらにエントリ書きました。IncUnicornのしくみはUnixらしくてきれいです。よかったら読んでみてください。middlewareで発生する例外とはアプリケーションで発生する例外を捕捉し、適切な処理をするのは一般的なことだと思います。middlewareで発生する例外はどうでしょうか?例えばMySQLを使っていてデータベースサーバに接続できない場合、ActiveRecord::ConnectionAdapters::ConnectionManagementというmiddlewareからMysql2::Errorが発生します。middlewareすると10番目に出てきます。MyApp::Application.routesウェブサーバはこの上にあり、自分のアプリケーションは一番下です。例外はrescueしなければ上へ上がって行きます。やってもアプリケーションではrescueできません。ハンドリングすればいいでしょうか?ActionDispatch::ShowExceptionsを使う?スタックを見ると上から6番目にActionDispatch::ShowExceptionsというのがあります。ソースを見ると、例外のクラス名をステータスコードにマップしていることがわかります。:insufficient_storage表示したいページをpublic/507.htmlとして置いておけば済みます。Storageも有りうるので、適切な措置とは言えません。middlewareで発生した例外はActionDispatch::Rescueというmiddlewareで捕捉できます。ActionDispatch::ShowExceptionsと違い、ActionDispatch::Rescueは例外クラスに対してハンドリングするRackアプリケーションを指定できます。failure.」と表示できます。Error)で十分でしょう。ポイントは、レスポンスボディとして任意の内容を返せることです。任意の内容を返せるということは、ユーザに適切なメッセージを見せたり、JavaScriptのフロントエンドにJSONなどで適切なステータスを返したりできるということです。上のrescue_fromはActionDispatch::Rescue#rescue_fromで、コントローラのマクロ風rescue_fromとは別物です。}はapplication.rbに書くにはちょっと生々しい印象です。コードらしい場所へ移動するにはどうしたらいいでしょうか。ActionDispatch::Rescue#rescue_fromの第2引数はRackアプリケーションですから、Rackアプリケーションとして振舞うクラスを指定してやれば済みます。ActionController::Metalを継承すればそういうクラスを簡単に作れます。endendapplication.rbには下のようになります。charなどのエラーになる問題の解決方法。readlineを使えば解決するらしい。readlineを導入する機能があって、Rubyをインストールした後に修正する手順は下の通り(追記:一度Rubyを消さないとうまく行かないので修正。リンク先の丸写しです)。installなお、2行目のruby-1.9.2-p180の部分はインストールしたRubyのバージョンに合わせて変えてください。readlineにしたら、Readline.refresh_lineがNotImplementedErrorになりました。refresh_lineを使う場合には向きませんね。tipsRSpecを2ヶ月くらい使って気づいた事と分からない事RSpec勉強会@万葉で発表してきたので、資料を公開します。資料の22ページで、subjectのためにdescribeを切ることについて「議論ありそう」と書いたんですが、やっぱり@ukstudioさんからツッコまれました。曰く、describeは振る舞いの主体を表すもので、処理の結果を指すものではないでしょうとのこと(と理解した)。同じcontextでsubjectを変えると書きやすくなる場合もやっぱりあって、この問題はまだまだ楽しめそうです。app.Autotestはテスト駆動開発において欠かせないツールです。1.9ではRspecの起動の遅く、イライラしている人も多いでしょう。Rspecの起動を早くするツールにSporkがありますが、以下のような問題があります:製品コードを更新してもリロードしてくれない(ぇruby-debugが使えないこのエントリではこれらの問題を解決していきます。目指すのは次のような環境です:appの下はもちろん、configの下を更新した場合もリロードしてテストしてくれる製品コードでもテストコードでも、debuggerと書いたらruby-debugが使えるSporkまずはベースの環境から作りましょう。my_app最初にRSpecとautotest、sporkを入れるために、Gemfileに以下の行を加えます。'spork'Gemfileを編集したらbundleしておきます。--bootstrapここで、表示される指示に従ってspec/spec_helper.rbを編集します。下のようにしておけばよいでしょう。doendまたSporkを有効にするため、rspec:installによって生成された.rspecファイルに--drbを加えておきます。--drbこれで素のAutotestとSporkの環境はできました。適当なコードをscaffoldして試してみてもいいでしょう。RAILS_ENV=testsporkを起動し、別のターミナルでautotestも実行します。sporkautotestさらに別のターミナルでテストコードを失敗するように修正するとすぐさまautotestが赤くなります。製品コードを壊した場合、テストは走りますが緑のままです。リロードさせる製品コードのリロードは、実は次の2つの問題に分けられます。Pagesに回避方法が載っています。下のようにspec/spec_helper.rbのRSpec.configureのブロックに1行加えます。endこれでapp以下を修正した場合でもリロードしてテストしてくれます。app以外、例えばconfig/application.rbやconfig/initializersの中は、rspecの起動を速くするためにプリロードしているので、sporkの再起動で解決します。これを自動的にやってくれるのがguard-sporkです。APIのRubyバインディングであるrb-fseventをインストールします。ここで使うguard-sporkは、後述するruby-debugのために私が改造したものです。'rb-fsevent'加えたらbundleしてguard-sporkの初期化をします。sporkそしてguardを起動。startsporkはguardが起動してくれます。config/application.rbなどを更新するとguardがsporkを再起動します。ところでguardが監視してくれるファイルの中にはconfig/routes.rbがないのですが、これは下の修正をすることでテストに反映できるようになります。endruby-debugを使うこの時点では、rdebugを起動してコードの中にdebuggerと書いても止まってくれません。実際のテストはDRbサーバであるsporkで動いているからです(たぶん)。Harper氏がrdebugのセッションをフォワードするプロキシを書いてくれました。これを使うと、debuggerが現れたときにsporkのターミナルにrdebugのプロンプトが出ます(autotestのターミナルではない)。一箇所RuntimeErrorが出るところがあるので、ここでは私の修正版を使います。curlなどでプロキシモジュールをspecディレクトリに入れます。spec/spork-ruby-debug.rbそしてそれをspec/spec_helper.rbからrequireします。'test'もちろんruby-debugもインストールしておきましょう。Gemfileに下の行を加えてbundleします。'ruby-debug19'bundleこれで完成です。execを付けるのを忘れずにguardを起動してください。start実はオリジナルのguard-sporkだとsporkのプロセスがbackgroundへ回されてしまってrdebugのプロンプトが取れないのですが、そこは私の修正版で回避してあります。以上の手順で作った環境をgithubに置きましたのでよろしければ参考にしてください。Rails勉強会@東京で発表した内容をまとめたものです。)OmniAuthは、TwitterやGoogleなど様々な認証サービスプロバイダを統一したインターフェースで使えるようにしてくれるgemです。非常に便利なのでさっそく使おうとしたのですが、テストの書き方がわからなくて躓いたので、調べてわかったことやサンプルコードを公開します。OmniAuthは単体でも使えるのですが、伝統的なユーザ名とパスワードによる認証もサポートすることを想定して、Deviseと併用する構成となっています。1.0認証の過程でTwitterに3回のHTTPリクエストが飛ぶそれらをスタブで受ける発表で使った資料を下に貼っておきます。最低限のことしか書かれていませんが、参考になれば。3ではroutesのDSLが完全に刷新されました。あの見難かったハッシュの塊が解かれて、:memberや:getなど予約語の役割をしていたシンボルはディレクティブになりました。3ではディレクティブになり、ユーザの与える値がシンボルとして残りました。ActionController::Routing::RouteSet::Mapperインスタンスであるmapが必要なくなっています。3のroutesについてまとめます。'users#show'になります。mapが不要になったことと、コントローラとアクションを1つの値で指定できることで簡潔になっていますね。逆に、オプションのパラメータは()で囲む必要があります。デフォルトルートは下のように定義されます。3では基本のmatchディレクティブに:asを付けます。3ではrootというディレクティブを使います。基本のmatchディレクティブでは、実は:toを省略できます。下の2つは同じことです。'users#show'さらに、パスのノード名がコントローラ名とアクションに一致するなら、それも省略可能です。よって下の2つは同じです。3でもresourcesとして使用可能です。:shopsresourcesはブロックを受け取り、その中で冒頭で紹介したmemberやgetといったディレクティブを使用できます。2と同様、has_manyの関係を定義できます。namespacenamespaceディレクティブを使うことで、パス(URL)とコントローラを任意の名前空間に入れることができます。下のように書くことで、パスは/admin/users、コントローラはapp/controllers/admin/users_controller.rbに置かれたAdmin::UsersControllerになります。3ではルーティングの機構自体がRackミドルウェアなので、別のRackアプリケーションを呼び出すようなルートも書けるようになりました。:toの先にSinatra::Baseの子クラスを書くことができます。3の特集を書かれました。routesGitの新機能を使ってHerokuへのpushを軽くするHerokuはRack専用のホスティングサービスで、Gitでpushすることでデプロイできるという特長があります。pushはブランチのヒストリを全て転送するため、実際のデプロイメントに必要ない過去のファイルも転送されてしまい、無駄です(バックアップとして使えるという考え方もあると思いますが、その目的であれば他にもっと効率的な方法があります)。1.7.2の新しい機能を使って、実際のデプロイメントに必要なファイルだけをpushする方法を説明します。1.7.2では、checkoutコマンドに--orphanというオプションが追加されました。commit.つまり、--orphanを付けて新しいブランチを作ることで、ヒストリから切り離されたコミットを作ることができます。fileとしてステージされた状態になります。README#ここでcommitすればdeployブランチ唯一のコミットができます。READMEshow-branchすることで、既存のブランチから完全に切り離されていることが分かります。deploy:master転送するオブジェクトは最小で済むはずです。