ActiveRecord::Base#update_all expected behaviour

Hi

I noticed that if in my code I use the following:

Photo.update_all("title = 'Ruby rocks' ", "id IN (#{@photo_ids})")

All my objects are properly updated but none of the filters/callbacks are triggered. Is that what's expected?

I have a before_update filter set on the Photo class and it gets totally ignored, I guess the only way to solve this issue is to enumerate through the objects and update them one after the other :frowning:

Thanks,

-Matt

I think it'd be nice to have 2 variations of mass update statements. Something like destroy_all and delete_all, where one variation does blind sql query ( like delete_all ) and other shows complete respect for AR ( destroy_all )

However, note that you can do following as of now :

ids = Photo.find(:all, :conditions => ["id IN ?", @photo_ids]).amp(&:id) Photo.update(ids, Hash.new( :title => "Ruby rocks" )

However, note that you can do following as of now :

ids = Photo.find(:all, :conditions => ["id IN ?", @photo_ids]).amp(&:id) Photo.update(ids, Hash.new( :title => "Ruby rocks" )

Will that create only 1 SQL query? and will that use my filters?

I guess amp(&:id) should read map(&:id) Also, I don't see why you would do:

ids = Photo.find(:all, :conditions => ["id IN ?", @photo_ids]).amp(&:id)

if we already have the ids.

Thanks,

-Matt

Oops my bad.

1. Yeah, it should be map(&:id).

2. Yeah, you won't need Photo.find(:all, :conditions => ["id IN ?", @photo_ids]).map(&:id) if you have ids already, I was just making it generic case where condition could be anything.

3. No.That will create ids.length+1 number of queries. And yes, it will use your filters.

Thanks Pratik,

I just confirmed that solution works but it doesn't answer my question about update_all not using custom filters. Is that a bug or an expected behaviour? (I understand that technically unless you do a single query at a time, filters aren't used)

Thanks,

-Matt

Yes, there is no way to run filters without instantiating each activerecord object, which means that at minimum you must fetch all the objects from the database.

There is currently no support for batching updates to activerecord objects which would be needed to support saving all the objects (which would include running the filters) with only one SQL query.

I think it's possible to implement something like this, but it may not be trivial. Filters can change the objects in which case it would be uncertain if those changes should also be included in the batched SQL update query or if they should just be ignored.

Thanks Pratik,

I just confirmed that solution works but it doesn't answer my question about update_all not using custom filters. Is that a bug or an expected behaviour? (I understand that technically unless you do a single query at a time, filters aren't used)

Yes, it's intended behaviour, it's not possible to fire the callbacks or validations unless you instantiate the records (use find), then call save.

update all is intended for situations where you don't need the callbacks or validations to fire.