Rails 7.0 Added Class Level update! Method To ActiveRecord::Base
June 13, 2021
Ruby on Rails has update_all
class method which is used to update a batch of records without running validations and callbacks defined in the model.
On the contrary, we can update batch of records using update
class method which also runs validations and callbacks defined in our model.
Let's see an example:
class Employee < ApplicationRecord
validate :salary_for_experience_level, on: :update
private
def salary_for_experience_level
if experience < 2 && salary >= 1_00_000
errors.add(:salary, "Invalid")
end
end
end
In our Employee
model, while trying to update the salary we have a validation check on employee having salary more than 1_00_000
and experience level less than 2 years.
We will now create two employee records as follows:
Employee.create! experience: 3, salary: 100000
Employee.create! experience: 1, salary: 80000
Having the salary validation in our Employee
model, let's try to update salary of all employees:
Employee.update(salary: 1_30_000)
#=> [#<Employee id: 1, salary: 130000, experience: 3>,
#<Employee id: 2, salary: 130000, experience: 1>]
Employee.all
#=> [#<Employee id: 1, salary: 130000, experience: 3>,
#<Employee id: 2, salary: 80000, experience: 1>]
As we see above, update
method partially updated employee record with id 1
but
silently failed to update the employee record with id 2
due to validation check.
Rails 7.0 has added update!
method to raise ActiveRecord::RecordInvalid
error for employee record with id 2
.
# After Rails 7.0
Employee.update!(salary: 1_50_000)
#=> Employee Load (0.2ms) SELECT "employees".* FROM "employees"
# TRANSACTION (0.1ms) begin transaction
# Employee Update (0.6ms) UPDATE "employees" SET "salary" = ?, "updated_at" = ? WHERE "employees"."id" = ? [["salary", 150000], ["updated_at", "2021-06-13 18:09:14.800151"], ["id", 1]]
# TRANSACTION (1.8ms) commit transaction
# Traceback (most recent call last):
# 1: from (irb):18:in `<main>'
# ActiveRecord::RecordInvalid (Validation failed: Salary Invalid)
Here is the link to the relevant pull request.
info@scriptday.com