Currently I have a route that looks like this:
resources :posts
I want to override the ‘show’ action so that I can display a url like this:
posts/:id/:slug
I am currently able to do this by adding a custom match route:
resources :posts
match 'posts/:id/:slug' => 'posts#show'
However, when I use the link_to helper, it does not use my custom show route.
<%= link_to 'show', post %> # renders /posts/123
How can I define my show route so that I can still use the link_to helper?
Update: As you can read in the following answers, you can override the route to the ‘show’ action, but it’s probably more work than it’s worth. It’s easier to just create a custom route:
# config/routes.rb
match 'posts/:id/:slug' => 'posts#show', as: 'post_seo'
# app/views/posts/index.html.erb
<%= link_to post.title, post_seo_path(post.id, post.slug) %>
You have two routes which point to
posts#show(you should be able to confirm this by runningrake routes), and your link is using the wrong one.When you call
link_to('show', post)the URL of the link is generated by callingurl_for(post)which (eventually, after passing through several other methods on the way) callspost_path(post). Since the route toposts#showthat was created by your call toresources(:posts)is namedpost, that is the route thatpost_pathgenerates.You also currently have inconsistent routes for the show, update and destroy actions which will probably cause you problems later on.
You can fix this by changing your routes to the following:
Unfortunately you still can’t use
link_to('show', post)just yet, because it relies on being able to usepost.to_paramas the single argument needed to build a path to a post. Your custom route requires two arguments, anidand aslug. So now your link code will need to look like this:You can get around that problem by defining your own
post_pathandpost_urlhelpers inapp/helpers/posts_helper.rb:Which means we’re finally able to use:
If that all seems like too much work, a common alternative is to use URLs that look more like
posts/:id-:slug, in which case you can stick with the standard RESTful routes and just override theto_parammethod in yourPostclass:You’ll also need to do a little bit of work splitting up
params[:id]into an ID and a slug before you can look up the relevant instance in your show, edit, update and destroy controller actions.