Ruby on Rails: How to override the 'show' route of a resource?
You have two routes which point to posts#show
(you should be able to confirm this by running rake routes
), and your link is using the wrong one.
When you call link_to('show', post)
the URL of the link is generated by calling url_for(post)
which (eventually, after passing through several other methods on the way) calls post_path(post)
. Since the route to posts#show
that was created by your call to resources(:posts)
is named post
, that is the route that post_path
generates.
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:
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'
Unfortunately you still can't use link_to('show', post)
just yet, because it relies on being able to use post.to_param
as the single argument needed to build a path to a post. Your custom route requires two arguments, an id
and a slug
. So now your link code will need to look like this:
link_to 'show', post_path(post.id, post.slug)
You can get around that problem by defining your own post_path
and post_url
helpers in 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
Which means we're finally able to use:
link_to 'show', post
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 the to_param
method in your Post
class:
def to_param
"#{id}-#{slug}"
end
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.
Override show resource route in Rails
In your routes.rb put:
get "some_resource" => "some_resource#show"
before the line
resources :some_resource
Then rails will pick up your "get" before it finds the resources... thus overriding the get /some_resource
In addition, you should specify:
resources :some_resource, :except => :index
although, as mentioned, rails won't pick it up, it is a good practice
Overriding a resource route to / (root) in Rails3: not changing the path helper?
Thank you for your answers, it helped me find the exact solution to my question:
resources :subscribers, :only => [:new, :create], :path => '', :path_names => {:new => ''}
Tested and working on Rails 3 :)
Overriding Resource Route in Rails 2
I believe routes are prioritized from top to bottom, the top one being highest priority and the bottom one the lowest. So consider switching your routes like this :
map.connect '/photos', :controller => 'photos',
:action => 'options_stuff', :conditions => {:method => :options }
map.resources :photos
Rails 5: How to overwrite route parameters for extra member route
You're duplicating your routes entries for cats
, and you've provided the block for declaring the preview
route on the entry missing the param name override. You need to provide the override and the block in the same route declaration.
Rails.application.routes.draw do
resources :cats, param: :name do
get :preview, on: :member
end
end
This gives you the route you want:
$ rake routes
Prefix Verb URI Pattern Controller#Action
preview_cat GET /cats/:name/preview(.:format) cats#preview
Rails 3 Routes: Override Topics#show with Posts#index
add this route
get "/topics/:topic_id" => redirect("/topics/%{topic_id}/messages")
UPD
without redirecting:
get "/topics/:id" => "topic::Messages#index"
Or, if you're using shallow
:
get "/topics/:id" => "messages#index"
resources :forums, :shallow => true, :except => :show do
resources :topics, :shallow => true, :except => :show do
resources :messages
end
end
If I want to override the resource path (e.g. post_path(@post)), where do I do that?
There are two sides to routing: route generation and route matching.
The route generation, as you point out, is quite easy. Override to_param
in any ActiveModel:
# In a model:
def to_param
# Use another column instead of the primary key 'id':
awesome_identifier.to_s
end
The route matching is less obvious. It is possible to specify :awesome_identifier
in place of every occurrence of :id
in the default resource routes. However, I have found that Rails will give you less resistance if you leave :id
in your routes, and only change the logic in your controller. Note that this is a trade-off, because fundamentally the :id
in your routes is not really correct.
# In a controller:
def index
@awesome_record = AwesomeModel.find_by_awesome_identifier(params[:id])
# ...
end
As you have noted, Rails has optimised a single use case: if you want the primary key to be used for quick record look-up, but still prefer a slug to be included in the URL for user-friendliness or search engine optimisation. In that case you can return a string of the form "#{id}-#{whatever}"
from the to_param
method, and everything after the dash will be ignored when feeding the same string back into the find
method.
Rails routing: override the action name in a resource/member block
Is the following better?
resources :stories do
member do
put 'collaborator' => 'controller_name#add_collaborator'
delete 'collaborator' => 'controller_name#remove_collaborator'
end
end
You should also check your routes by launching in a terminal:
$ rake routes > routes.txt
And opening the generated routes.txt file to see what routes are generated from your routes.rb file.
Modify routes in rails
If you have taken,
resources :users
Now change this route as follows,
get '/users/edit', to: 'users#edit', as: 'users_edit'
Now in your view file where you have edit link
, change the link to,
<%= link_to 'Edit', users_edit_path(:id => user.id) %>
Now this links to the edit action of users controller with an id parameter
.
Now, in the users controller file,
class UsersController < ApplicationController
def edit
// params[:id] will be the ID that you sent through the view file.
@user = User.find(params[:id])
end
end
Thats it, you are done with your custom route, now the route will be users/edit instead of users/:id/edit
In routes, override scope-defined name from w/in the scope block
No, I can't think of a way to do it without moving it outside the scope
block. Here's what I would put after that scope
block:
get 'author/books' => 'author#my_books', as: 'my_books'
Related Topics
How to Transpose Different Sized Ruby Arrays
How to Stop Rails' Built-In Server from Listening on 0.0.0.0 by Default
MAC Osx Lion and Ruby - [Fatal] Failed to Allocate Memory
Is the .Each Iterator in Ruby Guaranteed to Give the Same Order on the Same Elements Every Time
Session Not Destroyed When Closing Browser - Railstutorial.Org
Add a CSS Class to <%= F.Submit %>
Rails 3.1 - Changing Default Scaffold Views and Template
Best Way to Handle Dynamic CSS in a Rails App
Possible to Use Stylesheet.Css.Erb in Rails
Integrating @Font-Face Files into Rails Asset Pipeline
Why Is This Not a Syntax Error
Difference Between Lambda and -> Operator in Ruby
Tcp Socket Communication Between Processes on Heroku Worker Dyno
How to Run Code After Each Line in Ruby