mobile_viewの手直し
2006.09.13の記事"Ruby on Railsを携帯電話対応に"でRuby on Rails用のライブラリmobile_view.rbをご紹介しました。それ以来、すっかりお世話になりっぱなしなんですが、今回ちょっとした問題に気付きました。
いつの間にかセッションIDが変化していて、セッションに保持しているはずの内容を後続の処理で参照できなくなってしまう、というものです。auの携帯電話では何ら問題なく動いて、旧Vodafoneの携帯電話で現象が出ました。(DoCoMoの実機では未確認です。)
同僚と調査した結果、form_tagが生成する<FORM>のactionのURLが"?_session_id=xxx"という形式でセッションIDを含んでいるためと分かりました。
フォームについてはhiddenでセッションIDを渡すため、URLには含める必要がありません。元のコードでもその意図が読めます。しかし、(下記には示しませんが)メソッドrewrite_optionsもオーバライドしているために、メソッドform_tag_without_session_idが<FORM>を生成する際に、セッションIDを含んでしまうようです。
クライアントがPCやauの機種であれば、actionのURLとhiddenの両方にセッションID(しかもどちらも同じ値)が存在してもちゃんと動きました。旧Vodafoneの機種の場合のみ、後続の要求において"_session_id"の値が"xxxxxxxx?_session_id=xxxxxxxx"のような値になりました。英数字以外の文字を含むのでセッションIDとは見なさず、新たなセッションIDを生成してしまうがために、そこでセッションが切れたようです。
<FORM>の生成時にactionが"?_session_id=xxx"を含まないように修正すべきかも知れませんが、今回は含めてしまったセッションIDを後から削除する方法で対処してみました。変更部分は下記の中の数行です。処理の都合で行の順序が変化していますが、要するにgsubでセッションIDを見付けて空文字列に置換しているだけです。
元のコード
def form_tag(url_for_options = {}, options = {}, *parameters_for_url, &proc)
tag = form_tag_without_session_id(url_for_options, options, *parameters_for_url, &proc)
if controller.send(:is_mobile?)
session_key = ::ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_key] || '_session_id'
tag + hidden_field_tag(session_key, request.session.session_id)
else
tag
end
end
変更したコード
def form_tag(url_for_options = {}, options = {}, *parameters_for_url, &proc)
tag = form_tag_without_session_id(url_for_options, options, *parameters_for_url, &proc)
session_key = ::ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_key] || '_session_id'
tag.gsub!( /\?#{ session_key }=[0-9a-z]+/, "" )
if controller.send(:is_mobile?)
tag + hidden_field_tag(session_key, request.session.session_id)
else
tag
end
end
上記の変更後に同僚と何度か確認してみて、意図通りにセッションを維持できていることを確認しました。もうちょっと美しい(?)方法があると思いますが、まずは当面の作業を進めてからにします。より良い方法がありましたら、ぜひご助言をお願いします。
コメント
You can follow this conversation by subscribing to the comment feed for this post.