What is the correct way to set up the routes to allow an extra path element (a slug) to be passed to a URL in Rails 3. I'd like to not break some of the magic you get with show and new when you list a object as a resource.
Here is an example:
http://somewebserver.com/topics/1/lear开发者_如何学JAVAning-rails but I would still like this to work http://somewebserver.com/topics/1 and these http://somewebserver.com/topics/new http://somewebserver.com/topics/1/editWhile it's probably better to make your slugs look like "1-learning-rails", since Rails 3 now allows the use of Rack applications to handle routes, so you could do something like this:
# lib/topic_slugger.rb
class TopicSlugger
AD_KEY = "action_dispatch.request.path_parameters"
def self.call(env)
controller = (env["PATH_INFO"].split("/")[1].camelize+"Controller").constantize
glob = env[AD_KEY][:glob]
slug, action_name = nil
if glob
path_params = glob.split("/")
if path_params.length == 1
if ["new","edit"].include?(path_params.first)
# no slug present
action_name = path_params.first
else
slug = path_params.first
end
else
action_name = path_params.first
slug = path_params.last
end
end
env[AD_KEY][:slug] = slug if slug
action = if action_name # "new" or "edit"
action_name.to_sym
else
case env["REQUEST_METHOD"]
when "PUT" then :update
when "DELETE" then :destroy
else :show
end
end
controller.action(action).call(env)
end
end
# config/routes.rb
require 'topic_slugger'
Ztest::Application.routes.draw do
# handle show, new, edit, update, destroy
match 'topics/:id/*glob' => TopicSlugger
# handle index, create
resources :topics
end
This takes requests of the form "/topics/1/foo/bar"
and passes them to the TopicSlugger Rack app, which decides whether the glob contains a combination action/slug (like "new/learning-rails"
), or just a slug ("learning-rails"
), adds the slug to the environment's request parameters, then passes the environment to the controller action, which itself is a Rack application. "index" and "create" are handled normally by the resources
statement.
So for example "GET /topics/1/new/learning-rails"
would be dispatched to TopicsController#new
with a params hash of { :id => "1", :slug => "learning-rails, :glob => "new/learning-rails" }
Because the /
is considered a path separator, Rails encourage you to separate the ID from the slug
using a -
which is more "neutral".
See this screencast.
Otherwise, you need to pass a custom :id
validation and let Rails know that :id
can include /
, but it's not that simple.
精彩评论