Simple Rails routing problem
I am having another ruby nuby moment and can't seem to wrap my head around this simple problem.
I have this as a route:
resources :pages
I have this in my pages controller:
def testy
end
and I have this in app/views/pages/testy.html.erb
<h1>Testy</h1>
I am trying to access the page like so: http://localhost:3000/pages/testy
And I get the following error:
Couldn't find Page with ID=testy
Here is the log:
Started GET "/pages/testy" for 127.0.0.1 at Thu Dec 09 14:24:51 -0600 2010
Processing by PagesController#show as HTML
Parameters: {"id"=>"testy"}
[1m[35mPage Load (0.3ms)[0m SELECT "pages".* FROM "pages" WHERE ("pages"."id" = 0) LIMIT 1
Completed in 12ms
ActiveRecord::RecordNotFound (Couldn't find Page with ID=testy):
app/controllers/pages_controller.rb:11:in `show'
It's obvious by the log that it's trying to access #show, but why? I think it's a problem with my route. Can some开发者_StackOverflow社区one give me a quick pointer?
I was following the Rails Guides here and I think this is what is throwing me off "... the rule is that if you do not explicitly render something by the end of the controller action, rails will look for the action_name.html.erb template in the controllers view path and then render that, ..."
When you set up a RESTful route like resources :pages
, by default anything after pages/
in the URL is put into the params hash as an ID so pages/1
would give you a params hash that includes {:id => '1'}
(among other things like :controller
, :action
, etc.).
There is an exception for certain actions like pages/new
or pages/edit
. Rails is smart enough to know that 'new' and 'edit' are not IDs. You just need to tell rails that 'testy' is not an ID either.
You can define custom actions using member
or collection
inside a block attached to resources
like this:
resources :pages do
collection do
get :testy # will match pages/testy
get :foo
post :bar
end
member do
get :baz # will match pages/1/baz
end
end
Now rails will know that pages/testy
is a custom route and will not interpret 'testy' as an ID. Make sure your route names are never the same as your ID. In other words, if you had a Page
that had an id of testy
for some reason, you'd never be able to reach it given the above routes!
For deeper knowledge, I highly recommend the official rails guide on routes: http://guides.rubyonrails.org/routing.html
Kind of long, but definitely worth the time to read.
Option 1
resources :pages do
collection do
get :testy
end
end
results in:
testy_pages GET /pages/testy(.:format) {:action=>"testy", :controller=>"pages"}
Option 2
resources :pages do
member do
get :testy
end
end
results in:
testy_page GET /pages/:id/testy(.:format) {:action=>"testy", :controller=>"pages"}
Option 3
resources :pages do
get :testy
end
results in:
page_testy GET /pages/:page_id/testy(.:format) {:action=>"testy", :controller=>"pages"}
Any of these might be useful, though I think Option 1 is what you were asking for.
in your routes file
resources :pages do
get 'test'
end
that will work. replace with post if necessary
Don't forget to run rake routes
or write routing tests/specs
Since pages is a resource anything after it in the url will be an id
with the stock options.
If you want to have a definition with 'testy' as the name you need to add a named routed
to your routes.rb
such as:
map.test 'testy', :controller => "pages", :action => "test"
Then to link to this you will need to call <%= link_to "testy", testy_path %>
精彩评论