#165 Edit Multiple (revised)
Feb 25, 2013 | 15 minutes | Forms
Editing one record at a time can be tedious work. Here you will learn three different ways to edit multiple records at once using checkboxes.
- Download:
- source codeProject Files in Zip (130 KB)
- mp4Full Size H.264 Video (34.4 MB)
- m4vSmaller H.264 Video (18.1 MB)
- webmFull Size VP8 Video (23.3 MB)
- ogvFull Size Theora Video (42.5 MB)
Resources
Solution 1: Inline
products/index.html.erb
<%= form_tag discontinue_products_path, method: :put do %> ... <%= check_box_tag "product_ids[]", product.id %> ... <%= submit_tag "Discontinue Checked" %> <% end %>
config/routes.rb
resources :products do collection do put :discontinue end end
products_controller.rb
def discontinue Product.update_all({discontinued: true}, {id: params[:product_ids]}) redirect_to products_url end
Solution 2: Edit Individually
products/index.html.erb
<%= form_tag edit_multiple_products_path, method: :get do %> ... <%= check_box_tag "product_ids[]", product.id %> ... <%= submit_tag "Edit Checked" %> <% end %>
config/routes.rb
resources :products do collection do get :edit_multiple put :update_multiple end end
products_controller.rb
def edit_multiple @products = Product.find(params[:product_ids]) end def update_multiple @products = Product.update(params[:products].keys, params[:products].values) @products.reject! { |p| p.errors.empty? } if @products.empty? redirect_to products_url else render "edit_multiple" end end
products/edit_multiple.html.erb
<%= form_tag update_multiple_products_path, method: :put do %> <% @products.each do |product| %> <h2><%= product.name %></h2> <%= fields_for "products[]", product do |f| %> <% if product.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(product.errors.count, "error") %> prohibited this product from being saved:</h2> <ul> <% product.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <div class="field"> <%= f.label :name %><br /> <%= f.text_field :name %> </div> ... <% end %> <% end %> <div class="actions"> <%= submit_tag "Update" %> </div> <% end %>
Solution 3: Single Fieldset
products/index.html.erb
<%= form_tag edit_multiple_products_path, method: :get do %> ... <%= check_box_tag "product_ids[]", product.id %> ... <%= submit_tag "Edit Checked" %> <% end %>
config/routes.rb
resources :products do collection do get :edit_multiple put :update_multiple end end
products_controller.rb
def edit_multiple @products = Product.find(params[:product_ids]) end def update_multiple @products = Product.find(params[:product_ids]) @products.reject! do |product| product.update_attributes(params[:product].reject { |k,v| v.blank? }) end if @products.empty? redirect_to products_url else @product = Product.new(params[:product]) render "edit_multiple" end end
products/edit_multiple.html.erb
<%= form_tag update_multiple_products_path, method: :put do %> <ul> <% @products.each do |product| %> <li> <%= hidden_field_tag "product_ids[]", product.id %> <%= product.name %> <ul class="errors"> <% product.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </li> <% end %> </ul> <%= fields_for :product do |f| %> <div class="field"> <%= f.label :name %><br /> <%= f.text_field :name %> </div> <div class="field"> <%= f.label :price_modification %><br /> <%= f.text_field :price_modification %> </div> <div class="field"> <%= f.label :category_id %><br /> <%= f.collection_select :category_id, Category.order("name"), :id, :name, include_blank: true %> </div> <div class="field"> <%= f.label :discontinued %><br /> <%= f.select :discontinued, [["Yes", true], ["No", false]], include_blank: true %> </div> <% end %> <div class="actions"> <%= submit_tag "Update" %> </div> <% end %>
models/product.rb
attr_accessible :name, :price, :discontinued, :category_id, :price_modification validates_numericality_of :price attr_reader :price_modification def price_modification=(new_price) @price_modification = new_price if new_price.to_s.ends_with? "%" self.price += (price * (new_price.to_d/100)).round(2) else self.price = new_price end end