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