开发者

Rails 3 Routes - allowing for slugs

开发者 https://www.devze.com 2023-02-09 17:29 出处:网络
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

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/edit


While 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.

0

精彩评论

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