简体   繁体   中英

Rails: Custom nested controller actions

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

in your route file:

match 'request/accept/:id' => 'requests#accept', :as => :accept

and in view

link_to "Accept", accept_path(request) 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM