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
精彩评论