代码之家  ›  专栏  ›  技术社区  ›  Paweł Gościcki Ywain

在Rails中有漂亮的(过时的)RESTful URL

  •  6
  • Paweł Gościcki Ywain  · 技术社区  · 14 年前

    我希望我的网站有如下网址:

    example.com/2010/02/my-first-post
    

    我有我的 Post 模型与 slug 字段(“我的第一个帖子”)和 published_on 字段(我们将从中扣除URL中的年和月部分)。

    我想要我的 做个安静的模特,比如 url_for(@post) 像他们应该的那样工作,即:它应该生成前面提到的URL。

    有办法吗?我知道你需要超越 to_param 并拥有 map.resources :posts 具有 :requirements 选项集,但我不能让它全部工作。


    我快做完了,我90%都在那里。使用 resource_hacks plugin 我可以做到:

    map.resources :posts, :member_path => '/:year/:month/:slug',
      :member_path_requirements => {:year => /[\d]{4}/, :month => /[\d]{2}/, :slug => /[a-z0-9\-]+/}
    
    rake routes
    (...)
    post GET    /:year/:month/:slug(.:format)      {:controller=>"posts", :action=>"show"}
    

    在视图中:

    <%= link_to 'post', post_path(:slug => @post.slug, :year => '2010', :month => '02') %>
    

    产生适当的 example.com/2010/02/my-first-post 链接。

    我也希望这样做:

    <%= link_to 'post', post_path(@post) %>
    

    但它需要超越 托帕兰 模型中的方法。应该相当容易,除了事实 托帕兰 必须返回 String 不是 Hash 如我所愿。

    class Post < ActiveRecord::Base
      def to_param
       {:slug => 'my-first-post', :year => '2010', :month => '02'}
      end
    end
    

    结果在 can't convert Hash into String 错误。

    这似乎被忽略了:

    def to_param
      '2010/02/my-first-post'
    end
    

    因为它会导致错误: post_url failed to generate from {:action=>"show", :year=>#<Post id: 1, title: (...) (它错误地将@post对象分配给:year键)。我有点不懂如何破解它。

    5 回复  |  直到 13 年前
        1
  •  4
  •   Paweł Gościcki Ywain    14 年前

    map.resources :posts, :except => [:show]
    map.post '/:year/:month/:slug', :controller => :posts, :action => :show, :year => /\d{4}/, :month => /\d{2}/, :slug => /[a-z0-9\-]+/
    

    def default_url_options(options = {})
      # resource hack so that url_for(@post) works like it should
      if options[:controller] == 'posts' && options[:action] == 'show'
        options[:year] = @post.year
        options[:month] = @post.month
      end
      options
    end
    

    def to_param # optional
      slug
    end
    
    def year
      published_on.year
    end
    
    def month
      published_on.strftime('%m')
    end
    

    <%= link_to 'post', @post %>
    

    resources :posts
    match '/:year/:month/:slug', :to => "posts#show", :as => :post, :year => /\d{4}/, :month => /\d{2}/, :slug => /[a-z0-9\-]+/
    

    routing_test

    default_url_options @post @posts p @posts.each do |p|

        2
  •  4
  •   Community Dan Abramov    7 年前

    application_controller.rb

    def url_for(options = {})
      if options[:year].class.to_s == 'Post'
        post = options[:year]
        options[:year] = post.year
        options[:month] = post.month
        options[:slug] = post.slug
      end
      super(options)
    end
    

    url_for(@post)
    post_path(@post)
    link_to @post.title, @post
    etc.
    

    nice soul url_for of a custom RESTful resource (composite key; not just id)

        4
  •  1
  •   Tomas Markauskas    14 年前

    default_url_options ApplicationController

    post_path

    def default_url_options(options = {})
      if options[:controller] == "posts" && options[:year].is_a?Post
        post = options[:year]
        {
          :year  => post.created_at.year,
          :month => post.created_at.month,
          :slug  => post.slug
        }
      else
        {}
      end
    end
    

    post_path(@post)

    {:language=>#<Post id: 1, ...>, :controller=>"posts", :action=>"show"}
    

    post_path(:slug => @post)
    

    def default_url_options(options = {})
      if options[:controller] == "posts" && options[:slug].is_a?Post
        {
          :year  => options[:slug].created_at.year,
          :month => options[:slug].created_at.month
        }
      else
        {}
      end
    end
    

    Post.to_param

        5
  •  1
  •   DaMainBoss    13 年前