Reputation: 35
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.
Upvotes: 1
Views: 5743
Reputation: 26193
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
.
Upvotes: 1
Reputation: 3741
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
Upvotes: 0
Reputation: 8240
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.
Upvotes: 0