Ruby on Rails:如何覆盖资源的“show”路由?

目前我的路线看起来像这样:

resources :posts 

我想覆盖’show’动作,以便我可以显示如下的URL:

 posts/:id/:slug 

我目前能够通过添加自定义match路由来完成此操作:

 resources :posts match 'posts/:id/:slug' => 'posts#show' 

但是,当我使用link_to帮助程序时,它不使用我的自定义show route。

  # renders /posts/123 

如何定义我的show route以便仍然可以使用link_to helper?

更新:正如您可以阅读以下答案,您可以覆盖“显示”操作的路线,但它可能比它的价值更多的工作。 创建自定义路线更容易:

 # config/routes.rb match 'posts/:id/:slug' => 'posts#show', as: 'post_seo' # app/views/posts/index.html.erb  

您有两条路线指向posts#show (您应该能够通过运行rake routes来确认这一点),并且您的链接使用了错误的rake routes

当你调用link_to('show', post)时,链接的URL是通过调用url_for(post)生成的(最后,在路上经过其他几个方法之后)调用post_path(post) 。 由于您通过调用resources(:posts)创建的resources(:posts) post_path的路由命名为post ,这是post_path生成的路由。

您目前还有不一致的路由,用于显示,更新和销毁操作,这些操作可能会在以后引起您的问题。

您可以通过将路由更改为以下内容来解决此问题:

 resources :posts, :except => ['show', 'update', 'destroy'] get 'posts/:id/:slug' => 'posts#show', :as => 'post' put 'posts/:id/:slug' => 'posts#update' delete 'posts/:id/:slug' => 'posts#destroy' 

遗憾的是,您仍然无法使用link_to('show', post) ,因为它依赖于能够使用post.to_param作为构建post路径所需的单个参数。 您的自定义路由需要两个参数,一个id和一个slug 。 所以现在您的链接代码需要如下所示:

 link_to 'show', post_path(post.id, post.slug) 

您可以通过在app/helpers/posts_helper.rb定义自己的post_pathpost_url帮助app/helpers/posts_helper.rb来解决该问题:

 module PostsHelper def post_path(post, options={}) post_url(post, options.merge(:only_path => true)) end def post_url(post, options={}) url_for(options.merge(:controller => 'posts', :action => 'show', :id => post.id, :slug => post.slug)) end end 

这意味着我们终于可以使用:

 link_to 'show', post 

如果这一切看起来都太多了,那么常见的替代方法是使用看起来更像posts/:id-:slug URL,在这种情况下,您可以坚持使用标准的RESTful路由,并在Post类中覆盖to_param方法:

 def to_param "#{id}-#{slug}" end 

你还需要做一些工作,将params[:id]分成ID和slug,然后才能在你的show中查找相关实例,编辑,更新和破坏控制器动作。

 resources :posts, except: :show do get ":slug" => :show, as: "", on: :member end 

并定义帮助器

  def post_path post "/posts/#{post.id}/#{post.slug}" end 

分贝/迁移/ add_slug_to_articles.rb

 add_column :articles, :slug, :string add_index :articles, :slug 

车型/ article.rb

 class Article < ActiveRecord::Base extend FriendlyId friendly_id :name, use: :slugged def should_generate_new_friendly_id? new_record? end end 

要么...

 class Article < ActiveRecord::Base extend FriendlyId friendly_id :name, use: :history end 

http://railscasts.com/episodes/314-pretty-urls-with-friendlyid

https://github.com/norman/friendly_id