June 10, 2016
This blog is part of our Rails 5 series.
The update_all
method when called on an ActiveRecord::Relation
object
updates all the records without invoking any callbacks and validations on the
records being updated.
Rails 5 supports update method on an ActiveRecord::Relation object that runs callbacks and validations on all the records in the relation.
people = Person.where(country: 'US')
people.update(language: 'English', currency: 'USD')
Internally, the above code runs update
method on each Person
record whose
country is 'US'
.
Let's see what happens when update
is called on a relation in which
validations fail on few records.
We have a Note model. For simplicity let's add a validation that note_text
field cannot be blank for first three records.
class Note < ApplicationRecord
validate :valid_note
def valid_note
errors.add(:note_text, "note_text is blank") if id <= 3 && note_text.blank?
end
end
Now let's try and update all the records with blank note_text
.
> Note.all.update(note_text: '')
Note Load (0.3ms) SELECT `notes`.* FROM `notes`
(0.1ms) BEGIN
(0.1ms) ROLLBACK
(0.1ms) BEGIN
(0.1ms) ROLLBACK
(0.1ms) BEGIN
(0.1ms) ROLLBACK
(0.1ms) BEGIN
SQL (2.9ms) UPDATE `notes` SET `note_text` = '', `updated_at` = '2016-06-16 19:42:21' WHERE `notes`.`id` = 3
(0.7ms) COMMIT
(0.1ms) BEGIN
SQL (0.3ms) UPDATE `notes` SET `note_text` = '', `updated_at` = '2016-06-16 19:42:21' WHERE `notes`.`id` = 4
(1.2ms) COMMIT
(0.1ms) BEGIN
SQL (0.3ms) UPDATE `notes` SET `note_text` = '', `updated_at` = '2016-06-16 19:42:21' WHERE `notes`.`id` = 5
(0.3ms) COMMIT
(0.1ms) BEGIN
SQL (3.4ms) UPDATE `notes` SET `note_text` = '', `updated_at` = '2016-06-16 19:42:21' WHERE `notes`.`id` = 6
(0.2ms) COMMIT
=> [#<Note id: 1, user_id: 1, note_text: "", created_at: "2016-06-03 10:02:54", updated_at: "2016-06-16 19:42:21">,
#<Note id: 2, user_id: 1, note_text: "", created_at: "2016-06-03 10:03:54", updated_at: "2016-06-16 19:42:21">,
#<Note id: 3, user_id: 1, note_text: "", created_at: "2016-06-03 12:35:20", updated_at: "2016-06-03 12:35:20">,
#<Note id: 4, user_id: 1, note_text: "", created_at: "2016-06-03 14:15:15", updated_at: "2016-06-16 19:14:20">,
#<Note id: 5, user_id: 1, note_text: "", created_at: "2016-06-03 14:15:41", updated_at: "2016-06-16 19:42:21">,
#<Note id: 6, user_id: 1, note_text: "", created_at: "2016-06-03 14:16:20", updated_at: "2016-06-16 19:42:21">]
We can see that failure of validations on records in the relation does not stop us from updating the valid records.
Also the return value of update on AR Relation is an array of records in the relation. We can see that the attributes in these records hold the values that we wanted to have after the update.
For example in the above mentioned case, we can see that in the returned array,
the records with ids 1, 2 and 3 have blank note_text
values even though those
records weren't updated.
Hence we may not be able to rely on the return value to know if the update is successful on any particular record.
For scenarios where running validations and callbacks is not important and/or
where performance is a concern it is advisable to use update_all
method
instead of update
method.
If this blog was helpful, check out our full blog archive.