Hatena::ブログ(Diary)

130単位

2011-12-23

ApacheとRailsのリダイレクト比較

PCサイトと携帯サイトを端末ごとに振り分けるのに、jpmobileの判定メソッドがお手軽なのでRailsのredirect_toを当初利用していました。が、おそらくApacheリダイレクトさせたほうがパフォーマンスはいいはずです。ただ確信はなく、「推測するな、計測せよ」ということで調べてみました。

環境

Apache Bench

ab -n 100 -c 10 http://example.com/m/
結果サマリー
項目RailsApache
Requests per second63.3579.57
Time per request157.850125.677

というわけで単純な比較ではありますが、やはりApacheリダイレクトしたほうが2割ほど速いようです。

Rails
Server Software:        Apache/2.2.16
Server Hostname:        example.com
Server Port:            80

Document Path:          /m/
Document Length:        96 bytes

Concurrency Level:      10
Time taken for tests:   1.578500 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Non-2xx responses:      101
Total transferred:      54338 bytes
HTML transferred:       9696 bytes
Requests per second:    63.35 [#/sec] (mean)
Time per request:       157.850 [ms] (mean)
Time per request:       15.785 [ms] (mean, across all concurrent requests)
Transfer rate:          33.58 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       10   61  48.7    101     119
Processing:    22   86  52.9    117     303
Waiting:       21   85  52.6    117     295
Total:         33  147 100.1    218     420

Percentage of the requests served within a certain time (ms)
  50%    218
  66%    230
  75%    237
  80%    239
  90%    251
  95%    263
  98%    274
  99%    420
 100%    420 (longest request)
Apache
Server Software:        Apache/2.2.16
Server Hostname:        example.com
Server Port:            80

Document Path:          /m/
Document Length:        302 bytes

Concurrency Level:      10
Time taken for tests:   1.256765 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Non-2xx responses:      100
Total transferred:      52000 bytes
HTML transferred:       30200 bytes
Requests per second:    79.57 [#/sec] (mean)
Time per request:       125.677 [ms] (mean)
Time per request:       12.568 [ms] (mean, across all concurrent requests)
Transfer rate:          39.78 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       10   57  49.5     13     122
Processing:    11   60  49.9     17     139
Waiting:       10   58  49.9     15     138
Total:         21  118  99.4     28     245

Percentage of the requests served within a certain time (ms)
  50%     28
  66%    212
  75%    218
  80%    221
  90%    235
  95%    242
  98%    244
  99%    245
 100%    245 (longest request)

レスポンスヘッダ

参考までにレスポンスヘッダも。Railsのほうはすこし付加されています。

Rails
Cache-Control:no-cache
Connection:close
Content-Length:96
Content-Type:text/html; charset=utf-8
Date:Fri, 23 Dec 2011 16:07:36 GMT
Location:http://example.com/
Server:Apache/2.2.16 (Amazon)
Status:302
X-Powered-By:Phusion Passenger (mod_rails/mod_rack) 3.0.7
X-Runtime:0.068700
X-UA-Compatible:IE=Edge,chrome=1
Apache
Connection:close
Content-Length:302
Content-Type:text/html; charset=iso-8859-1
Date:Fri, 23 Dec 2011 16:12:57 GMT
Location:http://example.com/
Server:Apache/2.2.16 (Amazon)

開発効率

サーバーとしてのパフォーマンスはApacheが優れていますが、開発も含めて考えると、Railsにも利点があります。まず、記述が簡潔かつ柔軟なこと。jpmobileの判定メソッドなら携帯キャリアを羅列する必要はありませんし、params[:controller]やparams[:action]を使ったりもできます。それから、テストがしやすいこと。他と同じようにRSpec/Capybaraのintegration testで書けるのは保守もしやすいのではないかと思います*1

ステータスコード

ちなみに、

デスクトップ用ページから従来のモバイル端末用ページにGooglebot-Mobileをリダイレクトするなら、301か302のどちらを使っても構わない

no title

とのことです。UAの条件のもとで恒久的なものなので、個人的には301かなと思う次第です。


4774142239
Apacheポケットリファレンス (POCKET REFERENCE)

関連記事

*1Apacheでもできなくはないですが、外との通信となるためcapybara-webkitを使うなど工夫が必要です

2011-12-15

さいきんのRailsアプリで使ったgem 10個

最近は、運用中Railsアプリの管理画面をTwitter Bootstrapでリニューアルしたり、こまごまと機能追加なんかしたりしてました。そんな中で新たに使ったgemライブラリを簡単にまとめてみます。

Prawn

Haml-rails

erb2haml

  • no title
    • ERBのviewファイルを一括置換
    • Hamlの文法を覚える参考にもなる

Kaminari

  • no title
    • ページネーション
    • will_paginateよりもなんとなくこちら
    • will_paginateよりもプラガブルかつクリーンな作り(と思う)

SimpleForm

  • no title
    • フォーム生成補助
    • 記述は少なく済むけど凝ったレイアウトにはしづらい
    • 管理画面などとは相性良いはず

ShowFor

  • no title
    • 詳細画面生成補助
    • SimpleFormみたいな感じ

jpmobile

Airbrake

pry-rails

  • no title
    • rails console で pry
    • 今のところカラー表示しかメリット享受してないけどirbよりはいいのかなと

rails_best_practices


Twitter Bootstrap/Haml/SimpleFormなどによる管理画面は、慣れてきたらかなり軽快に開発できた気がします。記述量が少ないおかげで、変更や機能追加にも対応しやすいのがいいと思います。

あと、Airbrakeはおすすめです。


4797363827
Rails3レシピブック 190の技

2011-12-04

Rails 擬似配列型カラムと複数選択チェックボックス

多対多の関連をレコード内の1つのカラムで表現したいことがあると思います。片方が少ない種類でほぼ決まっており、テーブルにするまでもないような場合です。

ALBUMS = {'Perfume〜Complete Best〜' => 1, 'GAME' => 2, 'Δ' => 3, 'JPN' => 4}
  • ユーザーが好きなアルバムを選択できる (複数可)

f:id:deeeki:20111204084241p:image

こんな入力フォームの実装についてまとめてみます。Railからはずれているのでめんどくさいです。

環境

擬似配列型カラム

class User < ActiveRecord::Base
  serialize :fav_albums, Array
end

serializeクラスマクロを使います。第二引数にクラスを指定するとそれ以外を受け付けなくなります。MySQLでのカラムはTEXT型です。YAML化した文字列で格納されます。

FormTagHelper

FormBuilderのcheck_boxは真偽値のカラム用になっているため、check_box_tagを使います。

check_box_tag(name, value = "1", checked = false, options = {})

ActionView::Helpers::FormTagHelper
<%= form_for @user do |f| %>
  <%= hidden_field_tag 'user[fav_albums][]' %>
  <% ALBUMS.each do |label, value| %>
    <%= check_box_tag 'user[fav_albums][]', value, @user.fav_albums.include?(value), :id => "user_fav_albums_#{value}" %>
    <%= label %>
  <% end %>
<% end %>
  • 配列で受け取るためのモデル名つきname属性を自力で指定
  • checkedの判定を自力で指定
  • id属性は書かないと重複してしまうため優しさで指定
  • hidden要素は全てチェックなしでの更新をするために必要

FormBuilder

FormBuilderでやろうとするとどうなるか。

check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")

ActionView::Helpers::FormHelper
<%= form_for @user do |f| %>
  <% ALBUMS.each do |label, value| %>
    <%= f.check_box :fav_albums, {:name => "user[fav_albums][]", :id => "user_fav_albums_#{value}"}, value, nil %>
    <%= label %>
  <% end %>
<% end %>
  • checkedの判定は不要
  • hidden要素は不要
  • デフォルトだとname属性がuser[fav_albums]になってしまうので明示的に指定
  • id属性は優しさで(ry

そんなわけで、あまりFormBuilderの恩恵は受けられません。

SimpleForm

そこでSimpleFormというgemを利用すると、簡潔に書けます。

<%= simple_form_for @user do |f| %>
  <%= f.input :fav_albums, :collection => ALBUMS, :as => :check_boxes %>
<% end %>
  • name属性もid属性もchecked判定もうまいことやってくれる
    • さらにラベル表示やエラー表示まで完璧にこなす
  • ただしhidden要素は複数できる
  • 改行入れたりとか細かいカスタマイズはしにくい

アクセサメソッド

上記いづれかでHTMLはできましたが、データのやり取りに問題があります。

  • パラメータで渡されるのは文字列なので数値に変えないといけない
  • 空白を除去しないといけない

これらの解決のためにモデルにアクセサメソッドを追加します。

class User < ActiveRecord::Base
  serialize :fav_albums, Array

  def fav_albums=(value)
    write_attribute(:fav_albums, Array.wrap(value).reject{|v| v.blank? }.map{|v| v.to_i })
  end

  def fav_albums
    read_attribute(:fav_albums) || []
  end
end

ゲッターでは値がない場合に空の配列を返すようにしました。

これで書き込み/読み込みが期待通りに動きます。

参考リンク

4274068668
RailsによるアジャイルWebアプリケーション開発 第4版