auto_increment
auto_increment automatically generates sequential values for Active Record attributes.
Common use cases:
- Invoice numbers (
1,2,3) - Customer numbers (
1000,1001,1002) - Per-account sequences
- Letter sequences (
A,B, ...,Z,AA,AB)
Quick Start
Without the gem:
class Invoice < ApplicationRecord
before_create :set_number
private
def set_number
self.number = Invoice.maximum(:number).to_i + 1
end
endWith auto_increment:
class Invoice < ApplicationRecord
auto_increment :number
endInvoice.create!.number #=> 1
Invoice.create!.number #=> 2
Invoice.create!.number #=> 3Installation
Add the gem to your Gemfile:
gem "auto_increment"Then run:
bundle installUsage
The target column must exist in your database.
class Invoice < ApplicationRecord
auto_increment :number
endInteger Sequences
class Invoice < ApplicationRecord
auto_increment :number
endGenerated values:
1
2
3
4
...
Custom Starting Value
class Invoice < ApplicationRecord
auto_increment :number, initial: 1000
endGenerated values:
1000
1001
1002
...
String Sequences
class User < ApplicationRecord
auto_increment :code, initial: "A"
endGenerated values:
A
B
C
...
Z
AA
AB
...
String sequences follow the same pattern as Excel columns.
Scoped Sequences
Generate independent sequences within a scope:
class Invoice < ApplicationRecord
auto_increment :number, scope: :account_id
endResult:
Account 1: 1, 2, 3
Account 2: 1, 2, 3
Multiple scopes are also supported:
class Invoice < ApplicationRecord
auto_increment :number,
scope: [:account_id, :year]
endResult:
Account 1, 2026: 1, 2, 3
Account 1, 2027: 1, 2, 3
Account 2, 2026: 1, 2, 3
Using Model Scopes
model_scope applies one or more Active Record scopes before calculating the maximum value.
This is useful when:
- Bypassing a
default_scope - Including archived records
- Restricting the sequence to a subset of records
class User < ApplicationRecord
default_scope -> { where(active: true) }
scope :unscoped_all, -> { unscoped }
auto_increment :code,
scope: :account_id,
model_scope: :unscoped_all
endIn this example, the sequence is calculated using all records, including inactive ones.
Callback Timing
By default, values are assigned during before_create.
auto_increment :codeYou can change when the value is generated:
| Option | Callback |
|---|---|
:create |
before_create |
:save |
before_save |
:validation |
before_validation |
Example:
class Account < ApplicationRecord
auto_increment :code, before: :validation
validates :code, presence: true
endOverwriting Existing Values
By default, manually assigned values are preserved.
invoice.number = 500
invoice.saveTo always generate a new value:
auto_increment :number, force: trueConcurrency
For applications that may create records concurrently, enable locking:
auto_increment :number, lock: trueThis locks the record used to determine the next value before assigning it.
Options
auto_increment :number,
scope: [:account_id, :year],
model_scope: :unscoped_all,
initial: 1000,
force: true,
lock: true,
before: :validation| Option | Description | Default |
|---|---|---|
column |
Column to increment. Can be integer or string. | :code |
initial |
Starting value. Integer or string. | 1 |
scope |
Restricts the sequence to matching column values. | nil |
model_scope |
Applies Active Record scopes before calculating the maximum value. | nil |
force |
Overwrites an already assigned value. | false |
lock |
Enables locking when calculating the next value. | false |
before |
Callback timing (:create, :save, :validation). |
:create |
How It Works
When a record is created, auto_increment:
- Builds a query for the target column.
- Applies any configured scopes.
- Applies any configured model scopes.
- Finds the current maximum value.
- Calculates the next value.
- Assigns the value during the configured callback.
The generated value is stored in a normal database column and can be queried, indexed, and validated like any other attribute.
Compatibility
| Ruby | Rails |
|---|---|
| 3.3 | 7.1, 7.2 |
| 3.4 | 7.1, 7.2, 8.0, 8.1 |
| 4.0 | 7.2, 8.0, 8.1 |
For older Ruby and Rails versions, use:
gem "auto_increment", "1.5.2"License
Released under the MIT License. See LICENSE.txt.