Best Practice for Bulk Update in Controller

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)
  end
end

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

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.
  end

end

Here's another thread: Bulk Collection Manipulation through a REST (RESTful) API


Some minor additions to the @Robert Head's answer. In the Rails official reference there's a chapter "What is REST?" http://guides.rubyonrails.org/v2.3.11/routing.html#what-is-rest

This chapter references the REST's author Roy Fielding’s doctoral thesis. In Chapter "5.2.1.1 Resources and Resource Identifiers" of this thesis we can read:

http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_2_1_1

The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on.

So defining here a ProductCollection resource - with its 7 own RESTful actions - would nicely fit into the whole REST concept.


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 attributes
Customer.update_all :wants_email => true

# Conditions from the current relation also works
Book.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.