2012年3月23日 #ruby #rails #troubleshooting #rack

Rails 3.1以前のバージョンなら多分テスト実行時にこういう警告が出ることがあるかもしれません。

gems/rack-1.2.5/lib/rack/utils.rb:16: warning: regexp match /.../n against to UTF-8 string

このうるさい警告を消す方法を紹介します。

解決方法

rspecを使う場合はspec/spec_helper.rbに下記コードを最後に追記してください。

原因

Rack1.3からは解決できたらしいですが、Rails 3.1以前を使うならとりあえずこの方法で回避してもいいかと。
詳しくは:https://github.com/rack/rack/issues/41

2011年11月 9日 #ruby #rails #asset

ActionView/Helpers/AssetTagHelper、asset(画像、CSSなど)ホストのチューニングについての勉強メモです。

asset hostを指定

image_tag("rails.png")のhelper methodで生成するリンクはデフォルトでは同じホストのpublicフォルダを指しています。それを変更したい場合はconfig/environments/production.rbActionController::Base.asset_hostをいじります。

ActionController::Base.asset_host = "assets.example.com"
image_tag("rails.png")
# => <img alt="Rails" src="http://assets.example.com/images/rails.png?1230601161" />

asset hostを複数指定

ブラウザが一度に同一サーバには2つのコネクションしかできないそう(これは初めて知りました)で、asset同士のダウンロード完了するのを待たなければなりません。もし複数台のassetサーバがある場合はassets%d.example.comを使ってそれをコネクション数を増やせることができます。%dが指定されればRailsは0~3の4つの番号を付けて、並行して8つのコネクションができます。

ActionController::Base.asset_host = "assets%d.example.com"
image_tag("rails.png")
# => <img alt="Rails" src="http://assets.example.com/images/rails.png?1230601161" />
stylesheet_link_tag("application")
# => <link href="http://assets2.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />

カスタマイズ

もっと自分でカスタマイズしたい場合はsourceのprocパラメータを使えます。

ActionController::Base.asset_host = Proc.new { |source|
  "http://assets#{Digest::MD5.hexdigest(source).to_i(16) % 2 + 1}.example.com"
}
image_tag("rails.png")
# => <img alt="Rails" src="http://assets1.example.com/images/rails.png?1230601161" />
stylesheet_link_tag("application")
# => <link href="http://assets2.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />

特定のパスで始まるassetを特定のホストに指定する例:

ActionController::Base.asset_host = Proc.new { |source|
   if source.starts_with?('/images')
     "http://images.example.com"
   else
     "http://assets.example.com"
   end
 }
image_tag("rails.png")
# => <img alt="Rails" src="http://images.example.com/images/rails.png?1230601161" />
stylesheet_link_tag("application")
# => <link href="http://assets.example.com/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" type="text/css" />

さらにrequestの第二パラメータもあります。これでHTTPSの動作も制御できます。

ActionController::Base.asset_host = Proc.new { |source, request|
  if request.ssl?
    "#{request.protocol}#{request.host_with_port}"
  else
    "#{request.protocol}assets.example.com"
  end
}

Resources

http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html

2011年11月 7日 #ruby #rails #actionview #partial

例えば省略可能なフラグみたいなローカル変数をpartial viewに渡した時、そのデフォルト動作をpartial viewでハンドリングしたいですね。

調べてみたらdefined?local_assigns.has_key?が見つかりましたが、前者のほうはオススメできなさそうです。

Testing using defined? headline will not work. This is an implementation restriction.
http://api.rubyonrails.org/classes/ActionView/Base.html

実際やってみて、defined?でも動けるパターンはありますが、if/unless文で一行にしたらバグりました。なのでやはり* local_assigns.has_key?*を使いましょう。

Resources

http://stackoverflow.com/questions/238615/defined-method-in-ruby-and-rails
http://api.rubyonrails.org/classes/ActionView/Base.html

2011年11月 6日 #ruby #rails #rspec #capybara #webkit

Goal

ゴールと言うか目標はrspecのrequest(integration) testでjavascriptのテストをしたいです。が、いろいろハマってその問題と解決策を時間軸でメモしておきます。

Capybaraについてはある程度知ってる前提です。

javascriptのテストを書く

:js => trueでrspecのintegration testでjavascriptを有効に設定できます。
例:

ただデフォルトではjavascriptをサポートしないので、このspecは失敗します。解決の鍵はcapybara driverというものです。

capybara_webkit driver

なぜcapybara_webkit driver使う

Capybara ... currently comes with Rack::Test and Selenium support built in.

By default, Capybara uses the :rack_test driver, which is fast but does not support JavaScript. You can set up a different default driver for your features.

The capybara-webkit driver is for true headless testing. It uses QtWebKit to start a rendering engine process. It can execute JavaScript as well. It is significantly faster than drivers like Selenium since it does not load an entire browser.

のようにcapybaraは Rack::TestSeleniumのdriverがbuilt-inされて、デフォルトdriverは前者の:rack_testでjavascriptをサポートしないです。Seleniumはサポートしますが、それよりも速いのがcapybara-webkitなのでそれを採用しました。

capybara_webkit driverをインストール

Gemfileにcapybara_webkitを追記、bundle installします。webkitはQTが必要なので、もしそれがないとbundle installで失敗(エラー)します。後はspec_helper.rbにdefault driverをwebkitに設定します。

これで最初のサンプルspecは通るはずです。

データベースと絡んだテスト

上記のままだとデータベースと絡んだテストはまた失敗します。
例:

自分で確認してみたら、テスト時に作成したデータはjavascriptのテストで使えないっぽいです。Railscastsの記事によりますとspecのテストではデータベーストランザクションを使うが、それがselenium或いはwebkitでは使えないそうです。そのためにdatabase_cleanerというgemを使います。

database_cleanerを使う

config.use_transactional_fixturesをfalseにした時点でもうテスト自体は通るはずですが、データはずっとそのまま残ってしまうんです。database_cleanerは名の通りデータベースをテスト前後で綺麗な状態に保つことができます。

これでもう環境面の設定は完了です!

Resources

目的

OmniauthでTwitterに認証ログイン後、ログイン前と同じページにリダイレクトしたい

方法

libディレクトリのautoloadはRails libディレクトリのファイルをautoloadを参考してください。

解説

redirect_toパラメータ或いはrefererをログイン直前のリクエストから取ってセッションに保存するRack middwareの手法です。そしてsessions_controllerではセッション内に保存されたurlにリダイレクトし、セッションクリアしています。

もちろんTwitter以外のproviderでの認証&ログイン処理にも対応できます。

2011年10月21日 #ruby #sinatra

目的

Sinatraで静的なhtmlファイルをrenderする方法です。

現状

Sinatraでは色々なビューテンプレートをレンダリングできます。Haml、Erb、Sass、Markdown、CoffeeScript…が対応されていますが、HTMLは対応してないようです。html :indexで書いてもダメですね。

Sinatraのビューテンプレート

解決方法

File.readでファイルとして読み込むことですね。Sinatraはデフォルトの設定だとpublicフォルダ内のものをassetsとするそうです。

でちょっとリファクタリングしてhtml :indexのシンタックスでいけるようにしました。

参考

http://stackoverflow.com/questions/2437390/serving-static-files-with-sinatra