場当たり的にJpmobileをRails2.3に対応してみる
- 携帯電話の識別
- 携帯電話viewの自動振分け
というところについて
環境は
リクエストの拡張
Jpmobileはリクエストを拡張して、各リクエストからどのキャリア/機種であるのかを分かるようにしている
拡張しているのは ActionController::AbstractRequest だけれども
Rails2.3.2ではこのクラスはなくなってしまっている。
Rails2.2.2のrequest.class.ancestors
ActionController::CgiRequest ActionController::AbstractRequest ActiveSupport::Memoizable::Freezable Object ・・・
Rails2.3.2のrequest.class.ancestors
ActionController::Request Rack::Request Object ・・・
というわけで、リクエスト拡張のクラスをRack::Requestに変更する
jpmobile/lib/jpmobile/hook_abstract_request.rb
require 'action_pack' require 'jpmobile/request_with_mobile' if ::ActionPack::VERSION::MAJOR >=2 and ::ActionPack::VERSION::MINOR >= 3 class Rack::Request include Jpmobile::RequestWithMobile end else class ActionController::AbstractRequest include Jpmobile::RequestWithMobile end end
ビューの拡張
Jpmobileはビューを拡張して、
自動振り分けのために拡張しているのは
- ActionView::Base#_pick_template
- ActionView::Base#render_partial
だけれども、Rails2.3.2では_pick_templateメソッドがなくなってしまっている。
actionpack-2.2.2/lib/action_view/base.rb
def render(options = {}, local_assigns = {}, &block) #:nodoc: local_assigns ||= {} if options.is_a?(String) ActiveSupport::Deprecation.warn( "Calling render with a string will render a partial from Rails 2.3. " + "Change this call to render(:file => '#{options}', :locals => locals_hash)." ) render(:file => options, :locals => local_assigns) elsif options == :update update_page(&block) elsif options.is_a?(Hash) options = options.reverse_merge(:locals => {}) if options[:layout] _render_with_layout(options, local_assigns, &block) elsif options[:file] _pick_template(options[:file]).render_template(self, options[:locals]) elsif options[:partial] render_partial(options) elsif options[:inline] InlineTemplate.new(options[:inline], options[:type]).render(self, options[:locals]) elsif options[:text] options[:text] end end end
actionpack-2.3.2/lib/action_view/base.rb
def render(options = {}, local_assigns = {}, &block) #:nodoc: local_assigns ||= {} case options when Hash options = options.reverse_merge(:locals => {}) if options[:layout] _render_with_layout(options, local_assigns, &block) elsif options[:file] template = self.view_paths.find_template(options[:file], template_format) template.render_template(self, options[:locals]) elsif options[:partial] render_partial(options) elsif options[:inline] InlineTemplate.new(options[:inline], options[:type]).render(self, options[:locals]) elsif options[:text] options[:text] end when :update update_page(&block) else render_partial(:partial => options, :locals => local_assigns) end end
templateをとってくるのはActionView::Base#_pick_templateからActionView::PathSet#find_templateがやることになりました。
でもJpmobileの自動ビュー振り分けにはリクエストオブジェクトが必須です。ActionView::PathSetはリクエストオブジェクトをとれません。
(追記)てきとうすぎた・・下記では振り分けはうまくいきません。ActiveController::Baseの default_template_name あたりが拡張ポイントだとおもわれ
なのでActionView::Base#render自体をざっくり拡張してみました。
jpmobile/lib/jpmobile/hook_action_view.rb
class ActionView::Base #:nodoc: delegate :default_url_options, :to => :controller unless respond_to?(:default_url_options) if ::ActionPack::VERSION::MAJOR >=2 and ::ActionPack::VERSION::MINOR >= 3 ### Rails 2.3 or higher alias render_without_jpmobile render #:nodoc: alias render_partial_without_jpmobile render_partial #:nodoc: def render(options = nil, extra_options = {}, &block) if options[:file] mobile_path = mobile_template_path(options[:file]) options[:file]=mobile_path if mobile_path end render_without_jpmobile(options, extra_options, &block); end def render_partial(options = {}) #:nodoc: case partial_path = options[:partial] when String, Symbol, NilClass mobile_path = mobile_template_path(partial_path, true) options = options.merge(:partial => mobile_path) if mobile_path end render_partial_without_jpmobile(options) end
if ::ActionPack::VERSION::MAJOR >=2 and ::ActionPack::VERSION::MINOR >= 3 ### Rails 2.3 or higher def template_exists?(template_name) self.view_paths.find_template(template_name) ? true : false rescue ActionView::MissingTemplate false end elsif ::ActionPack::VERSION::MAJOR >=2 and ::ActionPack::VERSION::MINOR >= 2 ### Rails 2.2 def template_exists?(template_name) send(:_pick_template_without_jpmobile, template_name) ? true : false rescue ActionView::MissingTemplate false end else ### Rails 2.1 or lower def template_exists?(template_name) finder.file_exists?(template_name) end end
てきとうだ・・
とりあえず動く。
拡張範囲をrenderにしてるのは2.2の拡張からするとかなり大ざっぱなのでどっか影響して動かなくなりそうな気がする。
ActionView::PathSet#find_templateを拡張するのがいいんだろうけどリクエストオブジェクトがとれないのをどうしたらよいのだろう?
あと、JpmobileがRails2.3に全対応するにはtrans_sidをなんとかしないといけないっぽい。
テストを流してみる
Jpmobileのインストールディレクトリでrake test
さっそくエラー。
TestRequestがAbstractRequest継承だ。とりあえず対処。
jpmobile/test/helper.rb
if ::ActionPack::VERSION::MAJOR >=2 and ::ActionPack::VERSION::MINOR >= 3 module Rack class TestRequest < Request attr_accessor :user_agent end end else module ActionController class TestRequest < AbstractRequest attr_accessor :user_agent end end end
さらにエラー。ActionController::CgiRequestのinitialize(引数2個)がRails2.3では定義されてない。
lib/jpmobile/trans_sid.rb
module ActionController class CgiRequest alias_method :initialize_without_ext, :initialize def initialize(cgi, options = {}) initialize_without_ext(cgi, options) ENV['QUERY_STRING'] = query_string end end end
これもどげんかせんといかん。