module
Lustra::Model::HasSaving
Overview
This module handles saving models to the database and triggers lifecycle callbacks.
It's where the actual :create
, :update
, :destroy
, and :save
callbacks are triggered.
Key callback trigger points:
:save
callbacks: triggered for the entire save operation (wraps create/update):create
callbacks: triggered when a new record is created:update
callbacks: triggered when an existing record is updated:destroy
callbacks: triggered when a record is destroyed
The callbacks are triggered via with_triggers
which calls Lustra::Model::EventManager
Direct including types
Defined in:
lustra/model/modules/has_saving.crInstance Method Summary
-
#decrement(column : Symbol | String, by = 1)
Decrement a numeric column without saving to the database.
-
#decrement!(column : Symbol | String, by = 1)
Decrement a numeric column by a specific amount (default 1) without running validations or callbacks.
-
#delete
Delete the model from the database WITHOUT running callbacks.
-
#destroy
Destroy the model from the database WITH callbacks and validations.
-
#increment(column : Symbol | String, by = 1)
Increment a numeric column without saving to the database.
-
#increment!(column : Symbol | String, by = 1)
Increment a numeric column by a specific amount (default 1) without running validations or callbacks.
- #persisted? : Bool
- #reload : self
-
#save(on_conflict : Lustra::SQL::InsertQuery -> | Nil = nil)
Save the model.
- #save(&block)
-
#save!(on_conflict : Lustra::SQL::InsertQuery -> | Nil = nil)
Performs
#save
call, but instead of returningfalse
if validation failed, raiseLustra::Model::InvalidError
exception Automatically handles built associations -
#save!(&block : Lustra::SQL::InsertQuery -> )
Pass the
on_conflict
optional parameter via block. -
#save_with_associations(on_conflict : Lustra::SQL::InsertQuery -> | Nil = nil)
Save the model along with all built associations
-
#update(**args)
Set the fields passed as argument and call
#save
on the object -
#update!(**args)
Set the fields passed as argument and call
#save!
on the object -
#update_column(column : Symbol | String, value)
Update a single column directly in the database without running validations or callbacks.
-
#update_columns(columns : NamedTuple)
Update multiple columns directly in the database without running validations or callbacks.
-
#update_columns(columns : Hash(String, Lustra::SQL::Any))
Update multiple columns directly in the database without running validations or callbacks.
-
#update_columns(**columns)
Update multiple columns directly in the database without running validations or callbacks.
Instance Method Detail
Decrement a numeric column without saving to the database.
Only updates the in-memory value. Call #save!
to persist.
user.decrement(:attempts_left)
user.save! # Persist the change
Returns self
for chaining.
Decrement a numeric column by a specific amount (default 1) without running validations or callbacks. Updates the database directly and updates the in-memory value.
user.decrement!(:attempts_left) # Decrement by 1
user.decrement!(:balance, 10.5) # Decrement by 10.5
Returns self
for chaining.
Delete the model from the database WITHOUT running callbacks. Use this for performance when you don't need to trigger callbacks. The deleted model is not persisted anymore and can be saved again.
user.delete
user.persisted? # => false
Returns true
if successfully deleted, false
otherwise.
Destroy the model from the database WITH callbacks and validations.
This is the safe way to delete records as it triggers all :destroy
callbacks.
The destroyed model is not persisted anymore and can be saved again.
user.destroy # Triggers before(:destroy) and after(:destroy) callbacks
user.persisted? # => false
Returns true
if successfully destroyed, false
otherwise.
Increment a numeric column without saving to the database.
Only updates the in-memory value. Call #save!
to persist.
user.increment(:login_count)
user.save! # Persist the change
Returns self
for chaining.
Increment a numeric column by a specific amount (default 1) without running validations or callbacks. Updates the database directly and updates the in-memory value.
user.increment!(:login_count) # Increment by 1
user.increment!(:score, 10) # Increment by 10
user.increment!(:balance, -5.5) # Can use negative values
Returns self
for chaining.
Save the model. If the model is already persisted, will call UPDATE
query.
If the model is not persisted, will call INSERT
Optionally, you can pass a Proc
to refine the INSERT
with on conflict
resolution functions.
Return false
if the model cannot be saved (validation issue)
Return true
if the model has been correctly saved.
Example:
u = User.new
if u.save
puts "User correctly saved !"
else
puts "There was a problem during save: "
# do something with `u.errors`
end
on_conflict
optional parameter
Example:
u = User.new id: 123, email: "email@example.com"
u.save(-> (qry) { qry.on_conflict.do_update { |u| u.set(email: "email@example.com") } #update
# IMPORTANT NOTICE: user may not be saved, but will be still detected as persisted !
You may want to use a block for on_conflict
optional parameter:
u = User.new id: 123, email: "email@example.com"
u.save do |qry|
qry.on_conflict.do_update { |u| u.set(email: "email@example.com")
end
Performs #save
call, but instead of returning false
if validation failed,
raise Lustra::Model::InvalidError
exception
Automatically handles built associations
Pass the on_conflict
optional parameter via block.
Save the model along with all built associations
Update a single column directly in the database without running validations or callbacks. This is useful for updating columns that don't need validation (like counters, flags, timestamps).
user.update_column(:login_count, 10)
user.update_column(:last_login_at, Time.utc)
Warning: This bypasses:
- Validations
- Callbacks
- Timestamp updates (updated_at will NOT change)
Returns self
for chaining.
Update multiple columns directly in the database without running validations or callbacks.
user.update_columns(login_count: 10, last_login_at: Time.utc)
user.update_columns({status: "active", verified: true})
Warning: This bypasses:
- Validations
- Callbacks
- Timestamp updates (updated_at will NOT change)
Returns self
for chaining.
Update multiple columns directly in the database without running validations or callbacks.
user.update_columns(login_count: 10, last_login_at: Time.utc)
user.update_columns({status: "active", verified: true})
Warning: This bypasses:
- Validations
- Callbacks
- Timestamp updates (updated_at will NOT change)
Returns self
for chaining.
Update multiple columns directly in the database without running validations or callbacks.
user.update_columns(login_count: 10, last_login_at: Time.utc)
user.update_columns({status: "active", verified: true})
Warning: This bypasses:
- Validations
- Callbacks
- Timestamp updates (updated_at will NOT change)
Returns self
for chaining.