Rails 3.2, No Route Matches { :controller=>'xx

2019-06-05 02:30发布

问题:

I'm trying to edit multiple records with a checkbox form as shown in this Railscast. Rails has changed since then and I'm having trouble with routing and forms.

I have a PeopleController and I'm trying to make a form that will edit all of their phone numbers at once. Yes, I know this isn't a useful function, as there is normally no reason to change everyone's phone numbers to the same thing, but I'm just using this to get comfortable with the code - and it isn't working!

Here's what I've got:

people_controller:

class PeopleController < ApplicationController
  helper_method :sort_column, :sort_direction

  def index
    @people = Person.order(sort_column + " " + sort_direction)

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @people }
    end
  end

  # GET /people/1
  # GET /people/1.json
  def show
    @person = Person.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @person }
    end
  end

  # GET /people/new
  # GET /people/new.json
  def new
    @person = Person.new

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @person }
    end
  end

  # GET /people/1/edit
  def edit
    @person = Person.find(params[:id])
  end

  # POST /people
  # POST /people.json
  def create
  ...
  end

  # PUT /people/1
  # PUT /people/1.json
  def update
  ...
  end

  def update_multiple
    @people = Person.find(params[:people_ids])
    @people.each do |person|
      person.update_attributes!(params[:person].reject { |k,v| v.blank? })
    end
    flash[:notice] = "Updated people"
    redirect_to people_path
  end

  # DELETE /people/1
  # DELETE /people/1.json
  def destroy
  ...
  end

  private

  def sort_column
    Person.column_names.include?(params[:sort]) ? params[:sort] : "name"
  end

  def sort_direction
    %w[asc desc].include?(params[:direction]) ? params[:direction] : "asc"
  end

end

index.html.erb:

<h1>Listing people</h1>
<% form_tag edit_multiple_people_path do %>
<table>
  <tr>
    <th></th>
    <th><%= sortable "name" %></th>
    <th><%= sortable "phone" %></th>
    <th><%= sortable "created_at" %></th>
    <th></th>
    <th></th>
    <th></th>
  </tr>

<% @people.each do |person| %>
  <tr>
    <td><%= check_box_tag "people_ids[]", person.id %></td>
    <td><%= person.name %></td>
    <td><%= person.phone %></td>
    <td><%= person.created_at %></td>
    <td><%= link_to 'Show', person %></td>
    <td><%= link_to 'Edit', edit_person_path(person) %></td>
    <td><%= link_to 'Destroy', person, method: :delete, data: { confirm: 'Are you sure?' } %></td>
  </tr>
<% end %>
</table>
<% # submit_tag "Edit Checked" %>
<% end %>
<br />

<%= link_to 'New Person', new_person_path %>

edit_multiple.html.erb:

<%= form_for :person, :url => update_multiple_path, :html => { :method => :put } do |f| %>
  <ul>
    <% @people.each %>
      <li>
        <%= hidden_field_tag "people_ids[]", person.id %>
        <%=h person.name %>
      </li>
    <% end %>
  </ul>

  <p>
    <%= f.label :phone %><br />
    <%= f.text_field :phone %>
  </p>

  <p><%= f.submit "Submit" %></p>
<% end %>

Routes.rb:

  resources :people do
    collection do
      put 'update_multiple'
    end
  end

And rake routes:

update_multiple_people PUT    /people/update_multiple(.:format) people#update_multiple
                people GET    /people(.:format)                 people#index
                       POST   /people(.:format)                 people#create
            new_person GET    /people/new(.:format)             people#new
           edit_person GET    /people/:id/edit(.:format)        people#edit
                person GET    /people/:id(.:format)             people#show
                       PUT    /people/:id(.:format)             people#update
                       DELETE /people/:id(.:format)             people#destroy

EDIT:

My routes were messed up. They are now working properly as shown above.

回答1:

You're conflating singular and plural resources. The edit_multiple_path route is currently configured as a singular resource, meaning that it expects a single Person to be passed as an argument. However, by definition, you're trying to update multiple people at a single time – it doesn't make sense to use a singular route, in this case.

Instead, try a collection route:

# config/routes.rb
resources :people
    collection do
        post 'update_multiple/:people_ids', :action => 'update_multiple'
    end
end

This will make the following route available:

       update_multiple_invites POST   /invites/update_multiple/:people_ids(.:format) invites#update_multiple

EDIT:

In the index view, you'll need to output your forms in order for them to be displayed:

# app/views/people/index.html.erb
<%= form_tag edit_multiple_people_path do %>

# app/views/people/_edit_multiple.html.erb
<%= form_for :person, :url => update_multiple_people_path, :html => { :method => :put } do |f| %>

Note that <% %> interprets everything enclosed within, but does not output it. You need to use <%= %> in order to actually output the form's contents.

Also, don't forget that your partial needs the extension .erb in order for it to interpret Ruby code. Perhaps you've named it accordingly, but your post depicts the name edit_multiple.html without the .erb.



回答2:

On submit take a look at the code inspector and verify if you are getting routed to an GET request.

If you are getting a 404 that results in a GET request instead of a PUT request, it's because the :method => :put option relied on JavaScript. You'll need to make sure jquery-rails is properly integrated in your app.



回答3:

You are trying to get this route:

No route matches {:controller=>"people", :action=>"edit_multiple"}

but in route.rb you are including :id attribute witch is requred

people/:id/edit_multiple

So in form you need to include person id

try out following code to get this route {:controller=>"people", :action=>"edit_multiple"}

resources :people do               
 collection do         
  get :edit_multiple       
  put :update_multiple       
 end        
end