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.