RoutesでComponentリクエストを制御する、の結論。

以下はRails 1.2時代でもやっていたけれど、render_component がない 2.0 を見据えていた実装。


render_component の代わりに適当にHTTPリクエストを疑似生成すればいいんだけれど、せっかくなので、routes.rb に次のように書いておきます。

  map.connect 'components/:controller/:action/:id', :requirements => {:controller => /[a-z_]+\/[a-z_]+/i }

これで、 components/hoge/fuga/foo/bar のリクエストに対して、Hoge::FugaController#foo {:id => "bar"} が割り当てられます。さらにRESTfulなComponentを実現できるように、その直前に

# /routes.rb

  # load all routing files under components/**/_config/ directory
  Dir::entries(File.join(RAILS_ROOT, "components")).each do |dir|
    if dir != "." && dir != ".." &&
        File.exist?(File.join(RAILS_ROOT, "components", dir, "_config/routes.rb"))
      map.namespace(dir, :path_prefix =>"components/#{dir}") do |component_map|
        WebJourney::Routing::ComponentRoutes.mapper = component_map
        load File.join(RAILS_ROOT, "components", dir, "_config/routes.rb")
      end
    end
  end
  map.connect 'components/:controller/:action/:id', :requirements => {:controller => /[a-z_]+\/[a-z_]+/i }

を書いておくと、components/**/_config/routes.rb を起動時に読みに行くようになります。で、

# /components/**/_config/routes.rb

# add Component original routing
WebJourney::Routing::ComponentRoutes.draw do |map|

end

のような形で、あたかもconfig/routes.rb に書くのと同じような感じで(ActionController::Routing::Routes.draw が
WebJourney::Routing::ComponentRoutes に変わっただけ)かけるようになります。WebJourney::Routing::ComponentRoutes の実体は対したことはなくて、

# /plugin/webjourney/lib/webjourney/routing/component_routes.rb
module WebJourney
  module Routing
    class ComponentRoutes
      def self.mapper=(mapper)
        @@mapper = mapper
      end

      def self.draw
        yield @@mapper
      end
    end
  end
end

要するにnamespaceでprefixなどを構成しておいたmapに対してdrawするようなブロック呼び出しを書いておくだけです。

んで、最後の仕上げに、Viewの部分で、

def render_component(url, options)
  ..(snip) ..  
end

というメソッドが、

<div id="{AutoGenerated}">now loading...</div>
<script type="text/javascript">
Ajax.Updater.new("{AutoGenerated}", url, {:method => ... }
</script>

ってな具合に出力するようなヘルパーを書いておけば、同じことはできます。かつ、Ajaxでロードするので大抵の場合、体感速度が向上します(が、リソースは多く消費するようになります)。