Rails 7.1 makes increment_counter and decrement_counter accept a by argument
In Ruby on Rails,
the increment_counter
and decrement_counter
are functionalities offered by ActiveRecord.
These functions are utilized to increment or decrement the value within a designated column within a database table,
specifically targeting a particular record.
They prove handy for updating counts or statistical data associated with a record,
all while bypassing the necessity to fetch and store the complete record.
The basic syntax of the increment_counter
method is as follows:
Model.increment_counter(:column_name, id)
- Model: The name of the ActiveRecord model representing the database table.
- :column_name: The name of the column you want to increment.
- id: The ID of the specific record you want to increment the counter.
The increment_counter
method will increase the column value
by 1 each time it gets executed.
Before Rails 7.1
The increment_counter
and
decrement_counter
methods are used primarily to maintain
counter cache
columns that store aggregate values.
For example,
if you have a Company
model with a column named employees_count
and
you want to increment the view count of a specific company
with an ID of 1,
you would use:
Company.increment_counter(:employees_count, 1)
This would generate an SQL query that updates the employees_count
column
of the companies table for the record with an ID of 1.
The increment_counter
operates at the database level,
so it doesn't retrieve the actual record from the database.
This can be more efficient than loading the entire record,
incrementing the counter,
and
then saving it back to the database.
But there are a few cases where you might want to increase the value
of employees_count
by N, where N is greater than 1.
Before Rails 7.1, the possible ways were
- Call the
increment_counter
N times
N.times do
Company.increment_counter(:employees_count, 1)
end
- Call the
update_all
query
Company.where(id: id).update_all("employees_count = employees_count + 5")
This approach is less convenient than increment_counter
.
The increment_counter function automatically manages the usage of
COALESCE
and effectively addresses challenges related to concurrency.
- Call ActiveRecord::Persistence#increment on the company record
company = Company.find(1)
company.increment(:employees_count, 5)
The increment
method modifies the employees_count
within the memory
and
subsequently writes this modified value to the database.
However,
this approach could overwrite a recently updated value due to race conditions.
In Rails 7.1
Rails 7.1 makes increment_counter and decrement_counter accept a 'by' argument.
Company.increment_counter(:employees_count, 1, by: 5)
This modification will also align with the current increment methods within Rails.
These existing methods,
such as ActiveRecord::Persistence#increment
and ActiveSupport::CacheStore#increment
,
already incorporate the usage of a 'by' argument and an 'amount' argument,
respectively.
To know more about this feature, please refer to this PR.