# Copyright (c) 2006 KBMJ, Inc. # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. require 'iconv' class ::ActionController::Base before_filter :set_mobile_info before_filter :sjis_request after_filter :sjis_response def without_session_id(&block) begin @no_session_id_on_rewrite = true yield ensure @no_session_id_on_rewrite = false end end protected alias_method :rewrite_options_without_session_id, :rewrite_options # url_for などで URL を生成する際に _session_id を含める def rewrite_options(options) if is_mobile? && !@no_session_id_on_rewrite session_key = ::ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_key] || '_session_id' if session.respond_to?(:session_id) && session.session_id options = options.dup options.update session_key => request.session.session_id end end rewrite_options_without_session_id(options) end # レスポンスを Shift_JIS に変換 def sjis_response if convert_to_sjis? && (!headers["Content-Type"] || headers["Content-Type"] =~ %r{^text/html}) if is_mobile? begin response.body = Iconv.conv('cp932', 'UTF-8', response.body) rescue Iconv::IllegalSequence logger.warn "Failed to convert response with iconv: #{$!}" # OS X では iconv が「〜」を変換してくれないのでエラーが発生する。というわけで NKF で変換する response.body = NKF.nkf('-Ws -m0', response.body) end headers["Content-Type"] = "text/html; charset=Shift_JIS" end end end # リクエストのパラメータを Shift_JIS から UTF-8 に変換 # functional test の場合はリクエストがすでに UTF-8 になっているので変換しない def sjis_request if is_mobile? @original_params = params.clone filter_sjis_request if convert_to_sjis? end end def convert_to_sjis? if is_mobile? # SoftBank 3GC 端末では 903SH のように SJIS では絵文字を送出しない端末があるため、UTF-8 を使用する return false if 'SoftBank' == @mobile_carrier && '3GC' == @mobile_type !session[:skip_mobile_encoding_conversion] else false end end def filter_sjis_request # ハッシュ内の value を Shift_JIS から UTF-8 に変換 params.convert_nested_value!{|value| value.is_a?(String) ? Iconv.conv('UTF-8', 'cp932', value) : value} end def set_mobile_info begin ua = request.user_agent case ua when /^J-PHONE\// @mobile_carrier = 'SoftBank' @mobile_type = 'PDC' when /^(Vodafone|SoftBank)\// @mobile_carrier = 'SoftBank' @mobile_type = '3GC' when /^(J-EMULATOR|Vemulator)\// @mobile_carrier = 'SoftBank' # ウェブコンテンツヴューア (5.0.1.126) は Host ヘッダのポート部分にカンマが入るので削除 request.env["HTTP_HOST"] = request.host_with_port.gsub(/:([\d,]+)$/) {|s| s.gsub(/,/, '')} when /^DoCoMo\/2\.0 / @mobile_carrier = 'DoCoMo' @mobile_type = 'FOMA' when /^DoCoMo\// @mobile_carrier = 'DoCoMo' @mobile_type = 'PDC' when /UP\.Browser\// @mobile_carrier = 'au' end @is_mobile = !@mobile_carrier.nil? || true == session[:is_mobile] rescue NoMethodError # テストのときは user_agent メソッドが存在しないのでセッションから読み込む @is_mobile = true == (session && session[:is_mobile]) @mobile_carrier = (session && session[:mobile_carrier]) end # ダミー @mobile_carrier ||= 'DoCoMo' if @is_mobile true end private :set_mobile_info # モバイルかどうかを判定 def is_mobile? @is_mobile end end # View のテンプレート切り替え。 # モバイルの場合は app/views/mobile 以下からテンプレートを読み込みます。 class ::ActionView::Base private alias_method :full_template_path_without_mobile, :full_template_path def full_template_path(template_path, extension) if is_mobile? template = full_template_path_without_mobile("mobile/#{template_path}", extension) template = nil unless File.exist?(template) end template ||= full_template_path_without_mobile(template_path, extension) end alias_method :cached_template_extension_without_mobile, :cached_template_extension # mobile では cached_template_extension を使わない # (PC と同じキャッシュを使うと整合性がとれなくなるため) def cached_template_extension(template_path) return nil if is_mobile? cached_template_extension_without_mobile(template_path) end def is_mobile? if controller.is_a? ::ActionController::Base controller.send(:is_mobile?) else false end end end module ::ActionView::Helpers::FormTagHelper alias_method :form_tag_without_session_id, :form_tag def form_tag(url_for_options = {}, options = {}, *parameters_for_url, &proc) tag = controller.without_session_id{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 alias_method :start_form_tag, :form_tag end class Hash def convert_nested_value!(&block) each do |key, value| case value when Hash, Array value.convert_nested_value!{|value| yield(value)} else self[key] = yield(value) end end end end class Array def convert_nested_value!(&block) each_with_index do |value, i| case value when Array, Hash value.convert_nested_value!{|value| yield(value)} else self[i] = yield(value) end end end end