开发者

Creating Friendly Rails URLs

I have a slightly different take on a fairly common problem: SEO-friendly URLs. I have a PagesController, so my URLs currently are like (using restful routing):

/pages/some-content-title

This works just fine, but there is a hierarchical structure to the pages so I need the following:

/some-content-title routes to /pages/some-content-title

I can also get this to happen using:

match '*a', :to => 'errors#routing'

in my routes.rb and trapping it in ErrorsController as:

class ErrorsController < ApplicationController
  def routing
    Rails.logger.debug "routing error caught looking up #{params[:a]}"
    if p = Page.find_by_slug(params[:a])
      redirect_to(:controller => 'pages', :action => 'show', :id => p)
      return
    end
    render :file => "#{Rails.root}/public/404.html", :status => 404, :layout => false
  end
end

My question comes in the desired SEO elimination of the "pages/" part of the URL. What the S开发者_运维百科EO-dude wants (and here is where an example is key):

/insurance => :controller=>'pages', :id=>'insurance' # but the url in the address bar is /insurance

/insurance/car :controller=>'pages', :category=>'insurance', :id=>'car' # but the url in the address bar is /insurance/car

Is there a generic way for him to get his Google love and for me to keep the routes sane?

Thanks!


This is hard to do since you are redefining the parameters based on their presence (or absence) in the path. You could handle the globbed parameters in the controller, but then you don't get the URL that you want, and it requires a redirect.

Rails 3 lets you use a Rack application as an endpoint when creating routes. This (sadly underused) feature has the potential to make routing very flexible. For example:

class SeoDispatcher
  AD_KEY = "action_dispatch.request.path_parameters"

  def self.call(env)
    seopath = env[AD_KEY][:seopath]
    if seopath
      param1, param2 = seopath.split("/") # TODO handle paths with 3+ elements
      if param2.nil?
        env[AD_KEY][:id] = param1
      else
        env[AD_KEY][:category] = param1
        env[AD_KEY][:id] = param2
      end
    end
    PagesController.action(:show).call(env)
    # TODO error handling for invalid paths
  end
end
#

MyApp::Application.routes.draw do
  match '*seopath' => SeoDispatcher
end

will map as follows:

GET '/insurance'     => PagesController#show, :id => 'insurance'
GET '/insurance/car' => PagesController#show, :id => 'car', :category => 'insurance

and will retain the URL in the browser that your SEO dude is asking for.


There is a gem for this called friendly_id. See its github page

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜