Best Practice for Bulk Update in Controller
I see that you tagged your question with REST.
To do it RESTfully, you need to think about the collection or the update itself as the resource.
Say you are working with Product objects.
You might PUT to /product_batches/[some identifier], which would call ProductBatchesController#update, but then you are stuck wondering what goes in [some identifier]. You could make ProductBatch a singular resource and then you wouldn't need an id.
Better might be to POST to /product_bulk_updates, which would call ProductBulkUpdatesController#create
class ProductBulkUpdatesController < ApplicationController def create # your magic here # - update_all if you are making the same change to all Products # - looping through the hashes in params[products] if you are passing in distinct changes to each. endend
Here's another thread:Bulk Collection Manipulation through a REST (RESTful) API
I don't think there is a standard way. You may use update_attributes
(example with PostsController):
def update_bulk @posts = Post.where(:id => params[:ids]) # wrap in a transaction to avoid partial updates (and move to the model) if @posts.all? { |post| post.update_attributes(params[:post]) } redirect_to(posts_url) else redirect_to(:back) endend
Or use update_all
, but notice that neither callbacks nor validations will be called:
def update_bulk Post.where(:id => params[:ids]).update_all(params[:post]) redirect_to(posts_url)end
If you're fortunate enough to be working in Rails 3 then you should make sure to check out ActiveRecord::Relation#update_all or ActiveRecord::Base#update_all in Rails 2:
- Rails 3: http://apidock.com/rails/ActiveRecord/Relation/update_all
- Rails 2: http://apidock.com/rails/ActiveRecord/Base/update_all/class
It's much bettter to construct a single SQL update statement than do a full SQL round trip to update the elements.
Important Note: This is truely a bulk update using a SQL update statement. It will not instantiate any ActiveRecord objects since the update is performed purely in SQL. As such ActiveRecord callbacks and validations will not be called.
Examples from the URL above:
# Update all customers with the given attributesCustomer.update_all :wants_email => true# Conditions from the current relation also worksBook.where('title LIKE ?', '%Rails%').update_all(:author => 'David')
Note: As far as I can tell from posts on the internet, this functionality was somewhere between buggy and broken in Rails 3.0.3, 3.0.7 - 3.0.9.
I didn't discover the feature until 3.1.0, so I can't corroborate.