I want to setup a custom nested controller actions but I can't figure out the routing.
I keep getting the following error
No route matches [GET] "/assets"
routes.rb
resources :companies do
resources :requests do
match :accept
end
end
index.html.rb
<% @requests.each do |request| %>
<ul class="users">
<li>
<%= full_name(request.profile) %>
<%= request.status %>
<%= link_to "Accept",
:controller => "requests", :action => "accept",
:id => request.id %>
</li>
</ul>
<% end %>
There are a couple of problems: routing to the accept
action and building a URL to a nested resource.
Defining custom actions
You can add custom actions to your RESTful resources using this syntax:
resources :requests do
get 'accept', :on => :member
end
This will give you a route that looks like this:
requests/:id/accept
And you can generate paths in your views using:
accept_request_path(a_request)
The :on => :member
part indicates that you're routing to a new action on each individual request, rather than the collection of all requests. If you used :on => :collection
the route would be requests/accept
Nesting resources
When you nest resources:
resources :companies do
resources :requests do
get 'accept', :on => :member
end
end
You get routes that look like this, note that because the requests is nested inside companies the route includes both a company_id
and an id
:
companies/:company_id/requests/:id/accept
And helpers like this:
accept_company_request_path(a_company, a_request)
You could do this long-hand, as you're currently trying to do, with something like:
<%= link_to "Accept",
:controller => "requests", :action => "accept",
:id => request.id, :company_id => request.company.id %>
But it's easier to use the helpers:
<%= link_to "Accept", accept_company_request_path(request.company, request) %>
Appropriate verbs
Accept sounds a lot like something that updates your database in some way, and if that's the case you should consider using a PUT
request rather than a GET
request.
The HTTP/1.1 spec says that the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval (RFC2616, section 9) which has the real-world implication that non-human web clients — search engine indexers, browser extensions, etc. — are allowed to follow links (which make GET
requests) but not allowed to submit forms that make other types of requests.
If you do switch to using a PUT
request then the button_to
helper will come in handy. As with link_to
you can pass the controller, action, method, and all the parameters required by the route to button_to
:
<%= button_to 'Accept',
{:controller => :requests, :action => :accept,
:company_id => request.company, :id => request},
:method => :put %>
Or you can use the helpers to generate the path which is much easier:
<%= button_to 'Accept',
accept_company_request_path(request.company, request),
:method => :put %>
More documentation
- Adding more RESTful actions
- Nested resources
in your route file:
match 'request/accept/:id' => 'requests#accept', :as => :accept
and in view
link_to "Accept", accept_path(request)