-
Notifications
You must be signed in to change notification settings - Fork 2
Rails error: Routing Error: No route matches
If your error looks like ...
Routing Error
No route matches [GET] "/product/5"
Rails.root: /Users/sean/Desktop/product_app
... then either your URL is incorrect, or you need to define the route.
When a routing error is raised, rails will also show you your routes on the page, like so:
Routes match in priority from top to bottom
Helper | HTTP Verb | Path | Controller#Action |
---|---|---|---|
products_path | GET | /products(.:format) | products#index |
POST | /products(.:format) | products#create | |
new_product_path | GET | /products/new(.:format) | products#new |
edit_product_path | GET | /products/:id/edit(.:format) | products#edit |
product_path | GET | /products/:id(.:format) | products#show |
PATCH | /products/:id(.:format) | products#update | |
PUT | /products/:id(.:format) | products#update | |
DELETE | /products/:id(.:format) | products#destroy |
Take a look at your URL (in your browser's location bar), and try to match it against the Path column.
You can ignore the (.:format)
part of the Path if you're doing a regular http request.
You can reproduce your routing table on the command line by issuing:
rails routes
Figure out your Path by looking at your URL. For example, if I have the following in my browser's location bar:
http://localhost:3000/product/5
... then the path would be product/5
.
Now look at the paths in your routing table and try to match it against the path in your URL.
When matching against a Path in your routing table, break the pattern into segments, with each segment being in between two slashes. For example:
/products/new
- products
is one segment, new
is another segment.
Figure out if each segment is a static or dynamic segment:
- static segments do not begin with a
:
(colon) - dynamic segments begin with a
:
(colon)
Match each segment with your URL's path:
- static segments need to match exactly
- dynamic segments are wildcards, and can match against anything
If your URL is correct, but there's no route to match it against, then you need to define a route.
Open up config/routes.rb
and configure the route.
If this is a standard CRUD resource, then simply add:
resources :products
to your routes. (replacing products
with the name of your resource). Ensure your resource is pluralized.
If you just need a single route, you can define it like so:
get 'products/:id' => 'products#show'
Replacing:
-
get
with the http request method -
'products/:id'
with the pattern to match against -
'products#show'
with the controller and action (method)
For more details on routing, see the rails guide Rails Routing from the Outside In.
Perhaps you have the proper routes defined, and it's your URL that isn't correct.
For example, if I take:
http://localhost:3000/product/5
... and compare it to the routing table in the previous step, I notice that an s
is missing in my URL. It should be:
http://localhost:3000/products/5
Often it's the case you'll be using link_to
along with a URL or Path helper (methods that end with _url
and _path
).
The _url
and _path
helpers are generated from your routes.rb
file. You can see what helpers are available by running
rails routes
from your command line.
For example, if you see:
$ rails routes
Prefix Verb URI Pattern Controller#Action
products GET /products(.:format) products#index
POST /products(.:format) products#create
new_product GET /products/new(.:format) products#new
edit_product GET /products/:id/edit(.:format) products#edit
product GET /products/:id(.:format) products#show
PATCH /products/:id(.:format) products#update
PUT /products/:id(.:format) products#update
DELETE /products/:id(.:format) products#destroy
and looking at the Prefix
column. In the example above, the following methods are available:
products_path
products_url
new_product_path
new_product_url
edit_product_path
edit_product_url
product_path
product_url
The arguments (if any) you pass to these methods are determined by the number of dynamic segments in the URI Pattern.
For example, the following route:
products GET /products(.:format) products#index
does not have any dynamic segments, so no argument would be passed to the products_path
and products_url
methods. You might use this helper in a view like so:
link_to('View All Products', products_path)
In this example:
product GET /products/:id(.:format) products#show
There is one dynamic segment :id
, so you need to pass one argument to the product_path
and product_url
method. You might use this helper in a controller like so:
redirect_to product_path(@product)
If you're using nested routing and you have multiple dynamic segments, you need to pass a value for each dynamic segment within an array. For example, if you have the following route:
store_product GET /stores/:store_id/products/:id(.:format) products#show
then you're working with two dynamic segments (:store_id
and :id
). For example, you might use the path helper like so:
# In a view:
link_to("View info on #{@product.name}", store_product_path([@store, @product]))
# In a controller:
redirect_to store_product_path([@product.store, @product])
More info:
This is a living document. If you have anything to add, change or remove, please let us know. Or better yet, as it's a wiki, make the change yourself!