title: Testing Rack Routing Using rSpec
body: <p>I have a rule in my routes.rb:</p>
  
  <pre><code>constraints AssetRestrictor do
    match '*seopath' =&gt; SeoDispatcher
  end
  </code></pre>
  
  <p>Then in lib/seo_dispatcher.rb, I have this:</p>
  
  <pre><code>class SeoDispatcher
    AD_KEY = "action_dispatch.request.path_parameters"
  
    def self.call(env)
      seopath = env[AD_KEY][:seopath]
  
      if seopath
        params = seopath.split('/')           # get array of path components
        env[AD_KEY][:id] = params.last        # the real page name is the last element
        env[AD_KEY][:category] = params.first if params.length &gt; 1
      end
  
      Rails.logger.debug "routing to show #{env[AD_KEY]}"
      PagesController.action(:show).call(env)
      # TODO error handling for invalid paths
    end
  end
  
  class AssetRestrictor
    EXCEPTION_FILES = ['javascripts', 'stylesheets', 'autodiscover']
    def self.matches?(request)
      return false if request.method == 'POST'  # no post requests are SEO-ed
      EXCEPTION_FILES.each do |ex|
        return false if request.url.include?(ex)
      end
      true
    end
  end
  </code></pre>
  
  <p>And basically, the whole thing works. The idea is to peel off the last path component and match it to the slug for a page. SEO people tell me this is the cool way to trick search engines into ranking you higher.</p>
  
  <p>My snarky comments aside, I'm having trouble writing a test in rSpec that exercises this code. My first shot at it was:</p>
  
  <pre><code>describe SeoDispatcher do
    it "routes /insurance/charters-and-guides/how-to-buy-charter-boat-insurance to pages#show :id =&gt; how-to-buy-charter-boat-insurance" do
      { :get =&gt; "/insurance/charters-and-guides/how-to-buy-charter-boat-insurance"}.should route_to(
        :controller =&gt; 'pages',
        :action     =&gt; 'show',
        :id         =&gt; 'how-to-buy-charter-boat-insurance'
      )
    end
  end
  </code></pre>
  
  <p>But this simply doesn't exercise the Rack dispatch code. Does anyone know how one would (than cuking it) exercise the code? I really want to bring the parameters in from Rack instead of just doing <code>SeoDispatcher.call({"action_dispatch.request.path_parameters" =&gt; {:seopath =&gt; "/foo/bar"}})</code>.</p>
  
  <p>Thanks!</p>